Added mappings for a few messages.
[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_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
751 {
752     PAGER_INFO *infoPtr;
753     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
754
755     /* allocate memory for info structure */
756     infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
757     SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
758
759     /* set default settings */
760     infoPtr->hwndChild = (HWND)NULL;
761     infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
762     infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
763     infoPtr->nBorder = 0;
764     infoPtr->nButtonSize = 12;
765     infoPtr->nPos = 0;
766     infoPtr->nWidth = 0;
767     infoPtr->nHeight = 0;
768     infoPtr->bForward = FALSE;
769     infoPtr->TLbtnState = PGF_INVISIBLE;
770     infoPtr->BRbtnState = PGF_INVISIBLE;
771     infoPtr->direction = -1;
772
773     if (dwStyle & PGS_AUTOSCROLL)
774         FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
775     if (dwStyle & PGS_DRAGNDROP)
776         FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
777     /*
778          * If neither horizontal nor vertical style specified, default to vertical.
779          * This is probably not necessary, since the style may be set later on as
780          * the control is initialized, but just in case it isn't, set it here.
781          */
782     if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
783     {
784         dwStyle |= PGS_VERT;
785         SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
786     }
787
788     return 0;
789 }
790
791
792 static LRESULT
793 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
794 {
795     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
796     /* free pager info data */
797     COMCTL32_Free (infoPtr);
798     SetWindowLongA (hwnd, 0, 0);
799     return 0;
800 }
801
802 static LRESULT
803 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
804 {
805     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
806     LPRECT lpRect = (LPRECT)lParam;
807     RECT rcChildw, rcmyw, wnrc, lbrc, rbrc;
808     POINT cursor;
809
810     /*
811      * lParam points to a RECT struct.  On entry, the struct
812      * contains the proposed wnd rectangle for the window. 
813      * On exit, the struct should contain the screen
814      * coordinates of the corresponding window's client area.
815      */
816         
817     DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
818
819     if (PAGER_IsHorizontal(hwnd))
820     {
821         infoPtr->nWidth = lpRect->right - lpRect->left;
822         PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
823         GetWindowRect (infoPtr->hwndChild, &rcChildw);
824         MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
825         GetCursorPos (&cursor);
826         GetWindowRect (hwnd, &rcmyw);
827         if (PtInRect (&rcmyw, cursor)) {
828             GetWindowRect (hwnd, &wnrc);
829             lbrc = wnrc;
830             lbrc.right = lbrc.left + infoPtr->nButtonSize;
831             rbrc = wnrc;
832             rbrc.left = rbrc.right - infoPtr->nButtonSize;
833             TRACE("horz lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
834                   lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
835                   rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
836             if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
837                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
838             if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
839                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
840         }
841         if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
842             lpRect->left += infoPtr->nButtonSize;
843         if (infoPtr->BRbtnState) 
844             lpRect->right -= infoPtr->nButtonSize;
845     }
846     else
847     {
848         /* native does: (from trace of IE4 opening "Favorites" frame) 
849          *        DefWindowProc
850          *        WM_NOITFY  PGN_CALCSIZE w/ dwFlag=2
851          *        GetWindowRect (child, &rc)
852          *        MapWindowPoints (0, syspager, &rc, 2)
853          *        GetCursorPos( &cur )
854          *        GetWindowRect (syspager, &rc2)
855          *        PtInRect (&rc2, cur.x, cur.y) rtns 0
856          *        returns with rect empty
857          */
858         infoPtr->nHeight = lpRect->bottom - lpRect->top;
859         PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
860         GetWindowRect (infoPtr->hwndChild, &rcChildw);
861         MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
862         GetCursorPos (&cursor);
863         GetWindowRect (hwnd, &rcmyw);
864         if (PtInRect (&rcmyw, cursor)) {
865
866             /* native does:
867              *    GetWindowRect(pager, &rc)
868              *    PtInRect(btn-left????, cur.x, cur.y)
869              *    if true -> ???
870              *    PtInRect(btn-right????, cur.x, cur.y)
871              *    if true
872              *      RedrawWindow(pager, 0, 0, 5)
873              *      return TRUE
874              */
875
876             GetWindowRect (hwnd, &wnrc);
877             lbrc = wnrc;
878             lbrc.right = lbrc.left + infoPtr->nButtonSize;
879             rbrc = wnrc;
880             rbrc.left = rbrc.right - infoPtr->nButtonSize;
881             TRACE("vert lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
882                   lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
883                   rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
884             if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
885                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
886             if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
887                 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
888         }
889         if (infoPtr->TLbtnState)
890             lpRect->top += infoPtr->nButtonSize;
891         if (infoPtr->BRbtnState)
892             lpRect->bottom -= infoPtr->nButtonSize;
893         /* ???? */
894         if ((lpRect->bottom < 0) || (lpRect->bottom > infoPtr->nHeight))
895             lpRect->bottom = infoPtr->nHeight;
896     }
897
898     TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
899                 lpRect->right-lpRect->left,
900                 lpRect->bottom-lpRect->top,
901                 lpRect->left, lpRect->top);
902
903     return 0;
904 }
905
906 static LRESULT
907 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
908 {
909     PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
910     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
911     RECT rcWindow, rcBottomRight, rcTopLeft;
912     HDC hdc;
913     BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
914
915     if (dwStyle & WS_MINIMIZE)
916         return 0;
917
918     DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
919
920     if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
921         return 0;
922
923     GetWindowRect (hwnd, &rcWindow);
924     OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
925
926     rcTopLeft = rcBottomRight = rcWindow;
927     if (bHorizontal)
928     {
929         rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
930         rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
931     }
932     else
933     {
934         rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
935         rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
936     }
937
938     PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
939                      bHorizontal, TRUE, infoPtr->TLbtnState);
940     PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
941                      bHorizontal, FALSE, infoPtr->BRbtnState); 
942
943     ReleaseDC( hwnd, hdc );
944     return 0;
945 }
946
947 static INT 
948 PAGER_HitTest (HWND hwnd, LPPOINT pt)
949 {
950     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
951     RECT clientRect;
952     BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
953
954     GetClientRect (hwnd, &clientRect);
955
956     if (PtInRect(&clientRect, *pt))
957     {
958        /* TRACE("HTCLIENT\n"); */
959         return HTCLIENT;
960     }
961
962     if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
963     {
964         if (bHorizontal)
965         {
966             if (pt->x < clientRect.left)
967             {
968                 /* TRACE("HTLEFT\n"); */
969                 return HTLEFT;
970             }
971         }
972         else
973         {
974             if (pt->y < clientRect.top)
975             {
976                 /* TRACE("HTTOP\n"); */
977                 return HTTOP;
978             }
979         }
980     }
981
982     if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
983     {
984         if (bHorizontal)
985         {
986             if (pt->x > clientRect.right)
987             {
988                 /* TRACE("HTRIGHT\n"); */
989                 return HTRIGHT;
990             }
991         }
992         else
993         {
994             if (pt->y > clientRect.bottom)
995             {
996                /* TRACE("HTBOTTOM\n"); */
997                 return HTBOTTOM;
998             }
999         }
1000     }
1001
1002     /* TRACE("HTNOWHERE\n"); */
1003     return HTNOWHERE;
1004 }
1005
1006 static LRESULT
1007 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1008 {
1009     POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1010     ScreenToClient (hwnd, &pt);
1011     return PAGER_HitTest(hwnd, &pt);
1012 }
1013
1014 static LRESULT
1015 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1016 {
1017     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1018     BOOL notCaptured = FALSE;
1019
1020     switch(LOWORD(lParam))
1021     {
1022         case HTLEFT:
1023         case HTTOP:
1024             if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
1025                 infoPtr->TLbtnState = PGF_HOT;
1026             break;
1027         case HTRIGHT:
1028         case HTBOTTOM:
1029             if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
1030                infoPtr->BRbtnState = PGF_HOT;
1031             break;
1032         default:
1033             return FALSE;
1034     }
1035
1036     if (notCaptured)
1037     {
1038         TRACKMOUSEEVENT trackinfo;
1039
1040         TRACE("[%04x] SetCapture\n", hwnd);
1041         SetCapture(hwnd);
1042
1043         trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1044         trackinfo.dwFlags = TME_QUERY;
1045         trackinfo.hwndTrack = hwnd;
1046         trackinfo.dwHoverTime = HOVER_DEFAULT;
1047
1048         /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
1049         _TrackMouseEvent(&trackinfo);
1050
1051         /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
1052         if(!(trackinfo.dwFlags & TME_LEAVE)) {
1053             trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
1054  
1055            /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
1056            /* and can properly deactivate the hot button */
1057            _TrackMouseEvent(&trackinfo);
1058         }
1059
1060         SendMessageA(hwnd, WM_NCPAINT, 0, 0); 
1061     }
1062
1063     return TRUE;
1064 }
1065
1066 static LRESULT
1067 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1068 {
1069     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1070
1071     KillTimer (hwnd, TIMERID1);
1072     KillTimer (hwnd, TIMERID2);
1073
1074     TRACE("[%04x] ReleaseCapture\n", hwnd);
1075     ReleaseCapture();
1076
1077     /* Notify parent of released mouse capture */
1078     {
1079         NMHDR nmhdr;
1080         ZeroMemory (&nmhdr, sizeof (NMHDR));
1081         nmhdr.hwndFrom = hwnd;
1082         nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
1083         nmhdr.code = NM_RELEASEDCAPTURE;
1084         SendMessageA (GetParent(hwnd), WM_NOTIFY,
1085                         (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1086     }
1087
1088     /* make HOT btns NORMAL and hide gray btns */
1089     PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1090
1091     return TRUE;
1092 }
1093
1094 static LRESULT
1095 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1096 {
1097     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1098     BOOL repaintBtns = FALSE;
1099     POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1100     INT hit;
1101
1102     TRACE("[%04x]\n", hwnd);
1103         
1104     hit = PAGER_HitTest(hwnd, &pt);
1105
1106     /* put btn in DEPRESSED state */
1107     if (hit == HTLEFT || hit == HTTOP)
1108     {
1109         repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1110         infoPtr->TLbtnState = PGF_DEPRESSED;
1111         SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0); 
1112     }
1113     else if (hit == HTRIGHT || hit == HTBOTTOM)
1114     {
1115         repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1116         infoPtr->BRbtnState = PGF_DEPRESSED;
1117         SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0); 
1118     }
1119
1120     if (repaintBtns)
1121         SendMessageA(hwnd, WM_NCPAINT, 0, 0); 
1122
1123     switch(hit)
1124     {
1125     case HTLEFT:
1126         TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1127         PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1128         break;
1129     case HTTOP:
1130         TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1131         PAGER_Scroll(hwnd, PGF_SCROLLUP);
1132         break;
1133     case HTRIGHT:
1134         TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1135         PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1136         break;
1137     case HTBOTTOM:
1138         TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1139         PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1140         break;
1141     default:
1142         break;
1143     }
1144
1145     return TRUE;
1146 }
1147
1148 static LRESULT
1149 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1150 {
1151     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1152     TRACE("[%04x]\n", hwnd);
1153
1154     KillTimer (hwnd, TIMERID1);
1155     KillTimer (hwnd, TIMERID2);
1156
1157     /* make PRESSED btns NORMAL but don't hide gray btns */
1158     PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1159
1160     return 0;
1161 }
1162
1163 static LRESULT
1164 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1165 {
1166     POINT pt, ptorig;
1167     HDC hdc = (HDC)wParam;
1168     HWND parent;
1169
1170     /* native does:
1171      *   parent = GetParent(pager)
1172      *   pt.x=0; pt.y=0; ?????
1173      *   MapWindowPoints(pager, parent, &pt, 1)
1174      *   OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
1175      *   SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
1176      *   SetWindowOrgEx(hdc, 0, 0, 0)
1177      */
1178
1179     pt.x = 0;
1180     pt.y = 0;
1181     parent = GetParent(hwnd);
1182     MapWindowPoints(hwnd, parent, &pt, 1);
1183     OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
1184     SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
1185     SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
1186
1187
1188 #if 0
1189     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1190     HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1191     RECT rect;
1192
1193     GetClientRect (hwnd, &rect);
1194     FillRect ((HDC)wParam, &rect, hBrush);
1195
1196     /* background color of the child should be the same as the pager */
1197     if (infoPtr->hwndChild)
1198     {
1199         GetClientRect (infoPtr->hwndChild, &rect);
1200         FillRect ((HDC)wParam, &rect, hBrush);
1201     }
1202
1203     DeleteObject (hBrush);
1204 #endif
1205
1206     return TRUE;
1207 }
1208
1209
1210 static LRESULT
1211 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1212 {
1213     /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1214
1215     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1216     TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1217
1218     if (PAGER_IsHorizontal(hwnd))
1219         infoPtr->nHeight = HIWORD(lParam);
1220     else
1221         infoPtr->nWidth = LOWORD(lParam);
1222
1223     return PAGER_RecalcSize(hwnd);
1224 }
1225
1226
1227 static LRESULT WINAPI
1228 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1229 {
1230     PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1231
1232     if (!infoPtr && (uMsg != WM_CREATE))
1233         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1234
1235     switch (uMsg)
1236     {
1237         case PGM_FORWARDMOUSE:
1238             return PAGER_ForwardMouse (hwnd, wParam);
1239
1240         case PGM_GETBKCOLOR:
1241             return PAGER_GetBkColor(hwnd);
1242
1243         case PGM_GETBORDER:
1244             return PAGER_GetBorder(hwnd);
1245
1246         case PGM_GETBUTTONSIZE:
1247             return PAGER_GetButtonSize(hwnd);
1248
1249         case PGM_GETPOS:
1250             return PAGER_GetPos(hwnd);
1251
1252         case PGM_GETBUTTONSTATE:
1253             return PAGER_GetButtonState (hwnd, wParam, lParam);
1254
1255 /*      case PGM_GETDROPTARGET: */
1256
1257         case PGM_RECALCSIZE:
1258             return PAGER_RecalcSize(hwnd);
1259     
1260         case PGM_SETBKCOLOR:
1261             return PAGER_SetBkColor (hwnd, wParam, lParam);
1262
1263         case PGM_SETBORDER:
1264             return PAGER_SetBorder (hwnd, wParam, lParam);
1265
1266         case PGM_SETBUTTONSIZE:
1267             return PAGER_SetButtonSize (hwnd, wParam, lParam);
1268
1269         case PGM_SETCHILD:
1270             return PAGER_SetChild (hwnd, wParam, lParam);
1271
1272         case PGM_SETPOS:
1273             return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1274
1275         case WM_CREATE:
1276             return PAGER_Create (hwnd, wParam, lParam);
1277
1278         case WM_DESTROY:
1279             return PAGER_Destroy (hwnd, wParam, lParam);
1280
1281         case WM_SIZE:
1282             return PAGER_Size (hwnd, wParam, lParam);
1283
1284         case WM_NCPAINT:
1285             return PAGER_NCPaint (hwnd, wParam, lParam);
1286
1287         case WM_WINDOWPOSCHANGING:
1288             return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1289
1290         case WM_NCCALCSIZE:
1291             return PAGER_NCCalcSize (hwnd, wParam, lParam);
1292
1293         case WM_NCHITTEST:
1294             return PAGER_NCHitTest (hwnd, wParam, lParam);
1295
1296         case WM_SETCURSOR:
1297         {
1298             if (hwnd == (HWND)wParam)
1299                 return PAGER_SetCursor(hwnd, wParam, lParam);
1300             else /* its for the child */
1301                 return 0;
1302         }
1303
1304         case WM_MOUSEMOVE:
1305             if (infoPtr->bForward && infoPtr->hwndChild)
1306                 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1307             return TRUE;                        
1308
1309         case WM_MOUSELEAVE:
1310             return PAGER_MouseLeave (hwnd, wParam, lParam);     
1311
1312         case WM_LBUTTONDOWN:
1313             return PAGER_LButtonDown (hwnd, wParam, lParam);
1314
1315         case WM_LBUTTONUP:
1316             return PAGER_LButtonUp (hwnd, wParam, lParam);
1317
1318         case WM_ERASEBKGND:
1319             return PAGER_EraseBackground (hwnd, wParam, lParam);
1320 /*
1321         case WM_PAINT:
1322             return PAGER_Paint (hwnd, wParam); 
1323 */
1324         case WM_TIMER:
1325             /* if initial timer, kill it and start the repeat timer */
1326             if (wParam == TIMERID1)
1327             {
1328                 KillTimer(hwnd, TIMERID1);
1329                 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1330             }
1331
1332             KillTimer(hwnd, TIMERID2);
1333             if (infoPtr->direction > 0)
1334             {
1335                 PAGER_Scroll(hwnd, infoPtr->direction);
1336                 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);          
1337             }
1338             break;
1339
1340         case WM_NOTIFY:
1341         case WM_COMMAND:
1342             return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1343
1344         default:
1345             return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1346     }
1347
1348     return 0;
1349 }
1350
1351
1352 VOID
1353 PAGER_Register (void)
1354 {
1355     WNDCLASSA wndClass;
1356
1357     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1358     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1359     wndClass.lpfnWndProc   = (WNDPROC)PAGER_WindowProc;
1360     wndClass.cbClsExtra    = 0;
1361     wndClass.cbWndExtra    = sizeof(PAGER_INFO *);
1362     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1363     wndClass.hbrBackground = 0;
1364     wndClass.lpszClassName = WC_PAGESCROLLERA;
1365  
1366     RegisterClassA (&wndClass);
1367 }
1368
1369
1370 VOID
1371 PAGER_Unregister (void)
1372 {
1373     UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);
1374 }
1375