Writes to stdout and VGA_WriteChars routine now update both VGA
[wine/wine64.git] / dlls / comctl32 / pager.c
blobc1c1577a03f43993949b82be9d6ac6800527ca1c
1 /*
2 * Pager control
4 * Copyright 1998, 1999 Eric Kohl
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * NOTES
21 * Tested primarily with the controlspy Pager application.
22 * Susan Farley (susan@codeweavers.com)
24 * TODO:
25 * Implement repetitive button press.
26 * Adjust arrow size relative to size of button.
27 * Allow border size changes.
28 * Implement drag and drop style.
31 #include <string.h>
32 #include "winbase.h"
33 #include "commctrl.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(pager);
38 typedef struct
40 HWND hwndChild; /* handle of the contained wnd */
41 BOOL bNoResize; /* set when created with CCS_NORESIZE */
42 COLORREF clrBk; /* background color */
43 INT nBorder; /* border size for the control */
44 INT nButtonSize;/* size of the pager btns */
45 INT nPos; /* scroll position */
46 INT nWidth; /* from child wnd's response to PGN_CALCSIZE */
47 INT nHeight; /* from child wnd's response to PGN_CALCSIZE */
48 BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */
49 INT TLbtnState; /* state of top or left btn */
50 INT BRbtnState; /* state of bottom or right btn */
51 INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
52 } PAGER_INFO;
54 #define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
55 #define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
57 #define MIN_ARROW_WIDTH 8
58 #define MIN_ARROW_HEIGHT 5
60 #define TIMERID1 1
61 #define TIMERID2 2
62 #define INITIAL_DELAY 500
63 #define REPEAT_DELAY 50
65 /* the horizontal arrows are:
67 * 01234 01234
68 * 1 * *
69 * 2 ** **
70 * 3*** ***
71 * 4*** ***
72 * 5 ** **
73 * 6 * *
74 * 7
77 static void
78 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
80 INT x, y, w, h;
81 HPEN hOldPen;
83 w = r.right - r.left + 1;
84 h = r.bottom - r.top + 1;
85 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
86 return; /* refuse to draw partial arrow */
88 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
89 if (left)
91 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
92 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
93 MoveToEx (hdc, x, y, NULL);
94 LineTo (hdc, x--, y+5); y++;
95 MoveToEx (hdc, x, y, NULL);
96 LineTo (hdc, x--, y+3); y++;
97 MoveToEx (hdc, x, y, NULL);
98 LineTo (hdc, x, y+1);
100 else
102 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
103 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
104 MoveToEx (hdc, x, y, NULL);
105 LineTo (hdc, x++, y+5); y++;
106 MoveToEx (hdc, x, y, NULL);
107 LineTo (hdc, x++, y+3); y++;
108 MoveToEx (hdc, x, y, NULL);
109 LineTo (hdc, x, y+1);
112 SelectObject( hdc, hOldPen );
115 /* the vertical arrows are:
117 * 01234567 01234567
118 * 1****** **
119 * 2 **** ****
120 * 3 ** ******
124 static void
125 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
127 INT x, y, w, h;
128 HPEN hOldPen;
130 w = r.right - r.left + 1;
131 h = r.bottom - r.top + 1;
132 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
133 return; /* refuse to draw partial arrow */
135 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
136 if (up)
138 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
139 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
140 MoveToEx (hdc, x, y, NULL);
141 LineTo (hdc, x+5, y--); x++;
142 MoveToEx (hdc, x, y, NULL);
143 LineTo (hdc, x+3, y--); x++;
144 MoveToEx (hdc, x, y, NULL);
145 LineTo (hdc, x+1, y);
147 else
149 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
150 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
151 MoveToEx (hdc, x, y, NULL);
152 LineTo (hdc, x+5, y++); x++;
153 MoveToEx (hdc, x, y, NULL);
154 LineTo (hdc, x+3, y++); x++;
155 MoveToEx (hdc, x, y, NULL);
156 LineTo (hdc, x+1, y);
159 SelectObject( hdc, hOldPen );
162 static void
163 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
164 BOOL horz, BOOL topLeft, INT btnState)
166 HBRUSH hBrush, hOldBrush;
167 RECT rc = arrowRect;
169 if (!btnState) /* PGF_INVISIBLE */
170 return;
172 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
173 return;
175 hBrush = CreateSolidBrush(clrBk);
176 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
178 FillRect(hdc, &rc, hBrush);
180 if (btnState == PGF_HOT)
182 DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
183 if (horz)
184 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
185 else
186 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
188 else if (btnState == PGF_NORMAL)
190 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
191 if (horz)
192 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
193 else
194 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
196 else if (btnState == PGF_DEPRESSED)
198 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
199 if (horz)
200 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
201 else
202 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
204 else if (btnState == PGF_GRAYED)
206 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
207 if (horz)
209 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
210 rc.left++, rc.top++; rc.right++, rc.bottom++;
211 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
213 else
215 PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
216 rc.left++, rc.top++; rc.right++, rc.bottom++;
217 PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
221 SelectObject( hdc, hOldBrush );
222 DeleteObject(hBrush);
225 /* << PAGER_GetDropTarget >> */
227 static inline LRESULT
228 PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
230 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
231 TRACE("[%04x]\n", hwnd);
233 infoPtr->bForward = (BOOL)wParam;
235 return 0;
238 static inline LRESULT
239 PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
241 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
242 LRESULT btnState = PGF_INVISIBLE;
243 INT btn = (INT)lParam;
244 TRACE("[%04x]\n", hwnd);
246 if (btn == PGB_TOPORLEFT)
247 btnState = infoPtr->TLbtnState;
248 else if (btn == PGB_BOTTOMORRIGHT)
249 btnState = infoPtr->BRbtnState;
251 return btnState;
255 static inline LRESULT
256 PAGER_GetPos(HWND hwnd)
258 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
259 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nPos);
260 return (LRESULT)infoPtr->nPos;
263 static inline LRESULT
264 PAGER_GetButtonSize(HWND hwnd)
266 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
267 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nButtonSize);
268 return (LRESULT)infoPtr->nButtonSize;
271 static inline LRESULT
272 PAGER_GetBorder(HWND hwnd)
274 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
275 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nBorder);
276 return (LRESULT)infoPtr->nBorder;
279 static inline LRESULT
280 PAGER_GetBkColor(HWND hwnd)
282 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
283 TRACE("[%04x] returns %06lx\n", hwnd, infoPtr->clrBk);
284 return (LRESULT)infoPtr->clrBk;
287 static void
288 PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
290 NMPGCALCSIZE nmpgcs;
291 ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
292 nmpgcs.hdr.hwndFrom = hwnd;
293 nmpgcs.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
294 nmpgcs.hdr.code = PGN_CALCSIZE;
295 nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
296 nmpgcs.iWidth = getWidth ? *size : 0;
297 nmpgcs.iHeight = getWidth ? 0 : *size;
298 SendMessageA (GetParent (hwnd), WM_NOTIFY,
299 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
301 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
303 TRACE("[%04x] PGN_CALCSIZE returns %s=%d\n", hwnd,
304 getWidth ? "width" : "height", *size);
307 static void
308 PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
310 if (infoPtr->hwndChild)
312 RECT rcClient;
313 int nPos = infoPtr->nPos;
315 /* compensate for a grayed btn, which will soon become invisible */
316 if (infoPtr->TLbtnState == PGF_GRAYED)
317 nPos += infoPtr->nButtonSize;
319 GetClientRect(hwnd, &rcClient);
321 if (PAGER_IsHorizontal(hwnd))
323 int wndSize = max(0, rcClient.right - rcClient.left);
324 if (infoPtr->nWidth < wndSize)
325 infoPtr->nWidth = wndSize;
327 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
328 infoPtr->nWidth, infoPtr->nHeight,
329 -nPos, 0);
330 SetWindowPos(infoPtr->hwndChild, 0,
331 -nPos, 0,
332 infoPtr->nWidth, infoPtr->nHeight,
333 SWP_NOZORDER);
335 else
337 int wndSize = max(0, rcClient.bottom - rcClient.top);
338 if (infoPtr->nHeight < wndSize)
339 infoPtr->nHeight = wndSize;
341 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
342 infoPtr->nWidth, infoPtr->nHeight,
343 0, -nPos);
344 SetWindowPos(infoPtr->hwndChild, 0,
345 0, -nPos,
346 infoPtr->nWidth, infoPtr->nHeight,
347 SWP_NOZORDER);
350 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
354 static INT
355 PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
357 INT scrollRange = 0;
359 if (infoPtr->hwndChild)
361 INT wndSize, childSize;
362 RECT wndRect;
363 GetWindowRect(hwnd, &wndRect);
365 if (PAGER_IsHorizontal(hwnd))
367 wndSize = wndRect.right - wndRect.left;
368 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
369 childSize = infoPtr->nWidth;
371 else
373 wndSize = wndRect.bottom - wndRect.top;
374 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
375 childSize = infoPtr->nHeight;
378 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
379 if (childSize > wndSize)
380 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
383 TRACE("[%04x] returns %d\n", hwnd, scrollRange);
384 return scrollRange;
387 static void
388 PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
389 BOOL* needsResize, BOOL* needsRepaint)
391 if (infoPtr->nPos > 0)
393 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
394 if (infoPtr->TLbtnState != PGF_DEPRESSED)
395 infoPtr->TLbtnState = PGF_NORMAL;
397 else
399 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
400 infoPtr->TLbtnState = PGF_GRAYED;
403 if (scrollRange <= 0)
405 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
406 infoPtr->TLbtnState = PGF_GRAYED;
407 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
408 infoPtr->BRbtnState = PGF_GRAYED;
410 else if (infoPtr->nPos < scrollRange)
412 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
413 if (infoPtr->BRbtnState != PGF_DEPRESSED)
414 infoPtr->BRbtnState = PGF_NORMAL;
416 else
418 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
419 infoPtr->BRbtnState = PGF_GRAYED;
424 static void
425 PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
427 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
429 infoPtr->TLbtnState = PGF_NORMAL;
430 *needsRepaint = TRUE;
433 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
435 infoPtr->BRbtnState = PGF_NORMAL;
436 *needsRepaint = TRUE;
440 static void
441 PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
443 if (infoPtr->TLbtnState == PGF_GRAYED)
445 infoPtr->TLbtnState = PGF_INVISIBLE;
446 *needsResize = TRUE;
449 if (infoPtr->BRbtnState == PGF_GRAYED)
451 infoPtr->BRbtnState = PGF_INVISIBLE;
452 *needsResize = TRUE;
456 static void
457 PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
458 INT scrollRange, BOOL hideGrayBtns)
460 BOOL resizeClient = FALSE;
461 BOOL repaintBtns = FALSE;
463 if (scrollRange < 0)
464 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
465 else
466 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
468 if (hideGrayBtns)
469 PAGER_HideGrayBtns(infoPtr, &resizeClient);
471 if (resizeClient) /* initiate NCCalcSize to resize client wnd */ {
472 SetWindowPos(hwnd, 0,0,0,0,0,
473 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
474 SWP_NOZORDER | SWP_NOACTIVATE);
477 if (repaintBtns)
478 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
481 static LRESULT
482 PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
484 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
485 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
486 INT oldPos = infoPtr->nPos;
488 if ((scrollRange <= 0) || (newPos < 0))
489 infoPtr->nPos = 0;
490 else if (newPos > scrollRange)
491 infoPtr->nPos = scrollRange;
492 else
493 infoPtr->nPos = newPos;
495 TRACE("[%04x] pos=%d\n", hwnd, infoPtr->nPos);
497 if (infoPtr->nPos != oldPos)
499 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
500 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
501 PAGER_PositionChildWnd(hwnd, infoPtr);
504 return 0;
507 static LRESULT
508 PAGER_HandleWindowPosChanging(HWND hwnd, WPARAM wParam, WINDOWPOS *winpos)
510 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
512 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
514 /* don't let the app resize the nonscrollable dimension of a control
515 * that was created with CCS_NORESIZE style
516 * (i.e. height for a horizontal pager, or width for a vertical one) */
518 /* except if the current dimension is 0 and app is setting for
519 * first time, then save amount as dimension. - GA 8/01 */
521 if (PAGER_IsHorizontal(hwnd))
522 if (!infoPtr->nHeight && winpos->cy)
523 infoPtr->nHeight = winpos->cy;
524 else
525 winpos->cy = infoPtr->nHeight;
526 else
527 if (!infoPtr->nWidth && winpos->cx)
528 infoPtr->nWidth = winpos->cx;
529 else
530 winpos->cx = infoPtr->nWidth;
531 return 0;
534 DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, (LPARAM)winpos);
536 return 1;
539 static INT
540 PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
542 /* Must set the non-scrollable dimension to be less than the full height/width
543 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
544 * size, and experimentation shows that affect is almost right. */
546 RECT wndRect;
547 INT delta, h;
548 GetWindowRect(hwnd, &wndRect);
550 /* see what the app says for btn width */
551 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
553 if (infoPtr->bNoResize)
555 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
556 if (delta > infoPtr->nButtonSize)
557 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
558 else if (delta > 0)
559 infoPtr->nWidth += infoPtr->nButtonSize / 3;
562 h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
564 TRACE("[%04x] infoPtr->nWidth set to %d\n",
565 hwnd, infoPtr->nWidth);
567 return h;
570 static INT
571 PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
573 /* Must set the non-scrollable dimension to be less than the full height/width
574 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
575 * size, and experimentation shows that affect is almost right. */
577 RECT wndRect;
578 INT delta, w;
579 GetWindowRect(hwnd, &wndRect);
581 /* see what the app says for btn height */
582 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
584 if (infoPtr->bNoResize)
586 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
587 if (delta > infoPtr->nButtonSize)
588 infoPtr->nHeight += infoPtr->nButtonSize;
589 else if (delta > 0)
590 infoPtr->nHeight += infoPtr->nButtonSize / 3;
593 w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
595 TRACE("[%04x] infoPtr->nHeight set to %d\n",
596 hwnd, infoPtr->nHeight);
598 return w;
601 /******************************************************************
602 * For the PGM_RECALCSIZE message (but not the other uses in *
603 * this module), the native control does only the following: *
605 * if (some condition) *
606 * PostMessageA(hwnd, EM_FMTLINES, 0, 0); *
607 * return DefWindowProcA(hwnd, PGM_RECALCSIZE, 0, 0); *
609 * When we figure out what the "some condition" is we will *
610 * implement that for the message processing. *
611 ******************************************************************/
613 static LRESULT
614 PAGER_RecalcSize(HWND hwnd)
616 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
618 TRACE("[%04x]\n", hwnd);
620 if (infoPtr->hwndChild)
622 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
624 if (scrollRange <= 0)
626 infoPtr->nPos = -1;
627 PAGER_SetPos(hwnd, 0, FALSE);
629 else
631 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
632 PAGER_PositionChildWnd(hwnd, infoPtr);
636 return 1;
640 static LRESULT
641 PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
643 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
644 COLORREF clrTemp = infoPtr->clrBk;
646 infoPtr->clrBk = (COLORREF)lParam;
647 TRACE("[%04x] %06lx\n", hwnd, infoPtr->clrBk);
649 /* the native control seems to do things this way */
650 SetWindowPos(hwnd, 0,0,0,0,0,
651 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
652 SWP_NOZORDER | SWP_NOACTIVATE);
654 RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE);
656 return (LRESULT)clrTemp;
660 static LRESULT
661 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
663 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
664 INT nTemp = infoPtr->nBorder;
666 infoPtr->nBorder = (INT)lParam;
667 TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
669 PAGER_RecalcSize(hwnd);
671 return (LRESULT)nTemp;
675 static LRESULT
676 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
678 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
679 INT nTemp = infoPtr->nButtonSize;
681 infoPtr->nButtonSize = (INT)lParam;
682 TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
684 PAGER_RecalcSize(hwnd);
686 return (LRESULT)nTemp;
690 static LRESULT
691 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
693 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
694 INT hw;
696 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
698 if (infoPtr->hwndChild)
700 TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
702 if (PAGER_IsHorizontal(hwnd)) {
703 hw = PAGER_SetFixedHeight(hwnd, infoPtr);
704 /* adjust non-scrollable dimension to fit the child */
705 SetWindowPos(hwnd, 0, 0,0, hw, infoPtr->nHeight,
706 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
707 SWP_NOSIZE | SWP_NOACTIVATE);
709 else {
710 hw = PAGER_SetFixedWidth(hwnd, infoPtr);
711 /* adjust non-scrollable dimension to fit the child */
712 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, hw,
713 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
714 SWP_NOSIZE | SWP_NOACTIVATE);
717 /* position child within the page scroller */
718 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
719 0,0,0,0,
720 SWP_SHOWWINDOW | SWP_NOSIZE); /* native is 0 */
722 infoPtr->nPos = -1;
723 PAGER_SetPos(hwnd, 0, FALSE);
726 return 0;
729 static void
730 PAGER_Scroll(HWND hwnd, INT dir)
732 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
733 NMPGSCROLL nmpgScroll;
734 RECT rcWnd;
736 if (infoPtr->hwndChild)
738 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
739 nmpgScroll.hdr.hwndFrom = hwnd;
740 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
741 nmpgScroll.hdr.code = PGN_SCROLL;
743 GetWindowRect(hwnd, &rcWnd);
744 GetClientRect(hwnd, &nmpgScroll.rcParent);
745 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
746 nmpgScroll.iDir = dir;
748 if (PAGER_IsHorizontal(hwnd))
750 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
751 nmpgScroll.iXpos = infoPtr->nPos;
753 else
755 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
756 nmpgScroll.iYpos = infoPtr->nPos;
758 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
760 SendMessageA (hwnd, WM_NOTIFY,
761 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
763 TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
765 if (nmpgScroll.iScroll > 0)
767 infoPtr->direction = dir;
769 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
770 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
771 else
772 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
774 else
775 infoPtr->direction = -1;
779 static LRESULT
780 PAGER_FmtLines(HWND hwnd)
782 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
784 /* initiate NCCalcSize to resize client wnd and get size */
785 SetWindowPos(hwnd, 0, 0,0,0,0,
786 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
787 SWP_NOZORDER | SWP_NOACTIVATE);
789 SetWindowPos(infoPtr->hwndChild, 0,
790 0,0,infoPtr->nWidth,infoPtr->nHeight,
793 return DefWindowProcA (hwnd, EM_FMTLINES, 0, 0);
796 static LRESULT
797 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
799 PAGER_INFO *infoPtr;
800 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
802 /* allocate memory for info structure */
803 infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
804 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
806 /* set default settings */
807 infoPtr->hwndChild = (HWND)NULL;
808 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
809 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
810 infoPtr->nBorder = 0;
811 infoPtr->nButtonSize = 12;
812 infoPtr->nPos = 0;
813 infoPtr->nWidth = 0;
814 infoPtr->nHeight = 0;
815 infoPtr->bForward = FALSE;
816 infoPtr->TLbtnState = PGF_INVISIBLE;
817 infoPtr->BRbtnState = PGF_INVISIBLE;
818 infoPtr->direction = -1;
820 if (dwStyle & PGS_AUTOSCROLL)
821 FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
822 if (dwStyle & PGS_DRAGNDROP)
823 FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
825 * If neither horizontal nor vertical style specified, default to vertical.
826 * This is probably not necessary, since the style may be set later on as
827 * the control is initialized, but just in case it isn't, set it here.
829 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
831 dwStyle |= PGS_VERT;
832 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
835 return 0;
839 static LRESULT
840 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
842 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
843 /* free pager info data */
844 COMCTL32_Free (infoPtr);
845 SetWindowLongA (hwnd, 0, 0);
846 return 0;
849 static LRESULT
850 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
852 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
853 LPRECT lpRect = (LPRECT)lParam;
854 RECT rcChildw, rcmyw, wnrc, lbrc, rbrc;
855 POINT cursor;
856 BOOL resizeClient = FALSE;
857 BOOL repaintBtns = FALSE;
858 INT scrollRange;
861 * lParam points to a RECT struct. On entry, the struct
862 * contains the proposed wnd rectangle for the window.
863 * On exit, the struct should contain the screen
864 * coordinates of the corresponding window's client area.
867 DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
869 TRACE("orig rect=(%d,%d)-(%d,%d)\n",
870 lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
872 if (PAGER_IsHorizontal(hwnd))
874 infoPtr->nWidth = lpRect->right - lpRect->left;
875 PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
876 GetWindowRect (infoPtr->hwndChild, &rcChildw);
877 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
878 GetCursorPos (&cursor);
879 GetWindowRect (hwnd, &rcmyw);
881 /* Reset buttons and hide any grey ones */
882 scrollRange = infoPtr->nWidth - (rcmyw.right - rcmyw.left);
884 TRACE("nPos=%d, scrollrange=%d, nWidth=%d, myw=(%d,%d)-(%d,%d)\n",
885 infoPtr->nPos, scrollRange, infoPtr->nWidth,
886 rcmyw.left, rcmyw.top, rcmyw.right, rcmyw.bottom);
887 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
888 PAGER_HideGrayBtns(infoPtr, &resizeClient);
890 if (PtInRect (&rcmyw, cursor)) {
891 GetWindowRect (hwnd, &wnrc);
892 lbrc = wnrc;
893 lbrc.right = lbrc.left + infoPtr->nButtonSize;
894 rbrc = wnrc;
895 rbrc.left = rbrc.right - infoPtr->nButtonSize;
896 TRACE("horz lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
897 lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
898 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
899 if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
900 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
901 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
902 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
904 if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right))
905 lpRect->left += infoPtr->nButtonSize;
906 if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left))
907 lpRect->right -= infoPtr->nButtonSize;
909 else
911 /* native does: (from trace of IE4 opening "Favorites" frame)
912 * DefWindowProc
913 * WM_NOITFY PGN_CALCSIZE w/ dwFlag=2
914 * GetWindowRect (child, &rc)
915 * MapWindowPoints (0, syspager, &rc, 2)
916 * GetCursorPos( &cur )
917 * GetWindowRect (syspager, &rc2)
918 * PtInRect (&rc2, cur.x, cur.y) rtns 0
919 * returns with rect empty
921 infoPtr->nHeight = lpRect->bottom - lpRect->top;
922 PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
923 GetWindowRect (infoPtr->hwndChild, &rcChildw);
924 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
925 GetCursorPos (&cursor);
926 GetWindowRect (hwnd, &rcmyw);
928 /* Reset buttons and hide any grey ones */
929 scrollRange = infoPtr->nHeight - (rcmyw.bottom - rcmyw.top);
931 TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%d,%d)-(%d,%d)\n",
932 infoPtr->nPos, scrollRange, infoPtr->nHeight,
933 rcmyw.left, rcmyw.top,
934 rcmyw.right, rcmyw.bottom);
935 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
936 PAGER_HideGrayBtns(infoPtr, &resizeClient);
938 if (PtInRect (&rcmyw, cursor)) {
940 /* native does:
941 * GetWindowRect(pager, &rc)
942 * PtInRect(btn-left????, cur.x, cur.y)
943 * if true -> ???
944 * PtInRect(btn-right????, cur.x, cur.y)
945 * if true
946 * RedrawWindow(pager, 0, 0, 5)
947 * return TRUE
950 GetWindowRect (hwnd, &wnrc);
951 lbrc = wnrc;
952 lbrc.right = lbrc.left + infoPtr->nButtonSize;
953 rbrc = wnrc;
954 rbrc.left = rbrc.right - infoPtr->nButtonSize;
955 TRACE("vert lb rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
956 lbrc.left, lbrc.top, lbrc.right, lbrc.bottom,
957 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
958 if (PtInRect (&lbrc, cursor) && infoPtr->TLbtnState)
959 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
960 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
961 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
963 if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom))
964 lpRect->top += infoPtr->nButtonSize;
965 if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top))
966 lpRect->bottom -= infoPtr->nButtonSize;
967 /* ???? */
968 if ((lpRect->bottom < 0) || (lpRect->bottom > infoPtr->nHeight))
969 lpRect->bottom = infoPtr->nHeight;
972 TRACE("[%04x] client rect set to %dx%d at (%d,%d) BtnState[%d,%d]\n",
973 hwnd, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top,
974 lpRect->left, lpRect->top,
975 infoPtr->TLbtnState, infoPtr->BRbtnState);
977 return 0;
980 static LRESULT
981 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
983 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
984 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
985 RECT rcWindow, rcBottomRight, rcTopLeft;
986 HDC hdc;
987 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
989 if (dwStyle & WS_MINIMIZE)
990 return 0;
992 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
994 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
995 return 0;
997 GetWindowRect (hwnd, &rcWindow);
998 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
1000 rcTopLeft = rcBottomRight = rcWindow;
1001 if (bHorizontal)
1003 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
1004 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
1006 else
1008 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
1009 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
1012 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
1013 bHorizontal, TRUE, infoPtr->TLbtnState);
1014 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
1015 bHorizontal, FALSE, infoPtr->BRbtnState);
1017 ReleaseDC( hwnd, hdc );
1018 return 0;
1021 static INT
1022 PAGER_HitTest (HWND hwnd, LPPOINT pt)
1024 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1025 RECT clientRect;
1026 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1028 GetClientRect (hwnd, &clientRect);
1030 if (PtInRect(&clientRect, *pt))
1032 /* TRACE("HTCLIENT\n"); */
1033 return HTCLIENT;
1036 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
1038 if (bHorizontal)
1040 if (pt->x < clientRect.left)
1042 /* TRACE("HTLEFT\n"); */
1043 return HTLEFT;
1046 else
1048 if (pt->y < clientRect.top)
1050 /* TRACE("HTTOP\n"); */
1051 return HTTOP;
1056 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
1058 if (bHorizontal)
1060 if (pt->x > clientRect.right)
1062 /* TRACE("HTRIGHT\n"); */
1063 return HTRIGHT;
1066 else
1068 if (pt->y > clientRect.bottom)
1070 /* TRACE("HTBOTTOM\n"); */
1071 return HTBOTTOM;
1076 /* TRACE("HTNOWHERE\n"); */
1077 return HTNOWHERE;
1080 static LRESULT
1081 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1083 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1084 ScreenToClient (hwnd, &pt);
1085 return PAGER_HitTest(hwnd, &pt);
1088 static LRESULT
1089 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1091 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1092 BOOL notCaptured = FALSE;
1094 switch(LOWORD(lParam))
1096 case HTLEFT:
1097 case HTTOP:
1098 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
1099 infoPtr->TLbtnState = PGF_HOT;
1100 break;
1101 case HTRIGHT:
1102 case HTBOTTOM:
1103 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
1104 infoPtr->BRbtnState = PGF_HOT;
1105 break;
1106 default:
1107 return FALSE;
1110 if (notCaptured)
1112 TRACKMOUSEEVENT trackinfo;
1114 TRACE("[%04x] SetCapture\n", hwnd);
1115 SetCapture(hwnd);
1117 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
1118 trackinfo.dwFlags = TME_QUERY;
1119 trackinfo.hwndTrack = hwnd;
1120 trackinfo.dwHoverTime = HOVER_DEFAULT;
1122 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
1123 _TrackMouseEvent(&trackinfo);
1125 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
1126 if(!(trackinfo.dwFlags & TME_LEAVE)) {
1127 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
1129 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
1130 /* and can properly deactivate the hot button */
1131 _TrackMouseEvent(&trackinfo);
1134 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1137 return TRUE;
1140 static LRESULT
1141 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1143 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1145 KillTimer (hwnd, TIMERID1);
1146 KillTimer (hwnd, TIMERID2);
1148 TRACE("[%04x] ReleaseCapture\n", hwnd);
1149 ReleaseCapture();
1151 /* Notify parent of released mouse capture */
1153 NMHDR nmhdr;
1154 ZeroMemory (&nmhdr, sizeof (NMHDR));
1155 nmhdr.hwndFrom = hwnd;
1156 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1157 nmhdr.code = NM_RELEASEDCAPTURE;
1158 SendMessageA (GetParent(hwnd), WM_NOTIFY,
1159 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1162 /* make HOT btns NORMAL and hide gray btns */
1163 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1165 return TRUE;
1168 static LRESULT
1169 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1171 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1172 BOOL repaintBtns = FALSE;
1173 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1174 INT hit;
1176 TRACE("[%04x]\n", hwnd);
1178 hit = PAGER_HitTest(hwnd, &pt);
1180 /* put btn in DEPRESSED state */
1181 if (hit == HTLEFT || hit == HTTOP)
1183 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1184 infoPtr->TLbtnState = PGF_DEPRESSED;
1185 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1187 else if (hit == HTRIGHT || hit == HTBOTTOM)
1189 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1190 infoPtr->BRbtnState = PGF_DEPRESSED;
1191 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1194 if (repaintBtns)
1195 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1197 switch(hit)
1199 case HTLEFT:
1200 TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1201 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1202 break;
1203 case HTTOP:
1204 TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1205 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1206 break;
1207 case HTRIGHT:
1208 TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1209 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1210 break;
1211 case HTBOTTOM:
1212 TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1213 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1214 break;
1215 default:
1216 break;
1219 return TRUE;
1222 static LRESULT
1223 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1225 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1226 TRACE("[%04x]\n", hwnd);
1228 KillTimer (hwnd, TIMERID1);
1229 KillTimer (hwnd, TIMERID2);
1231 /* make PRESSED btns NORMAL but don't hide gray btns */
1232 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1234 return 0;
1237 static LRESULT
1238 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1240 POINT pt, ptorig;
1241 HDC hdc = (HDC)wParam;
1242 HWND parent;
1244 /* native does:
1245 * parent = GetParent(pager)
1246 * pt.x=0; pt.y=0; ?????
1247 * MapWindowPoints(pager, parent, &pt, 1)
1248 * OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
1249 * SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
1250 * SetWindowOrgEx(hdc, 0, 0, 0)
1253 pt.x = 0;
1254 pt.y = 0;
1255 parent = GetParent(hwnd);
1256 MapWindowPoints(hwnd, parent, &pt, 1);
1257 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
1258 SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
1259 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
1262 #if 0
1263 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1264 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1265 RECT rect;
1267 GetClientRect (hwnd, &rect);
1268 FillRect ((HDC)wParam, &rect, hBrush);
1270 /* background color of the child should be the same as the pager */
1271 if (infoPtr->hwndChild)
1273 GetClientRect (infoPtr->hwndChild, &rect);
1274 FillRect ((HDC)wParam, &rect, hBrush);
1277 DeleteObject (hBrush);
1278 #endif
1280 return TRUE;
1284 static LRESULT
1285 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1287 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1289 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1290 TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1292 if (PAGER_IsHorizontal(hwnd))
1293 infoPtr->nHeight = HIWORD(lParam);
1294 else
1295 infoPtr->nWidth = LOWORD(lParam);
1297 return PAGER_RecalcSize(hwnd);
1301 static LRESULT WINAPI
1302 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1304 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1306 if (!infoPtr && (uMsg != WM_CREATE))
1307 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1309 switch (uMsg)
1311 case EM_FMTLINES:
1312 return PAGER_FmtLines(hwnd);
1314 case PGM_FORWARDMOUSE:
1315 return PAGER_ForwardMouse (hwnd, wParam);
1317 case PGM_GETBKCOLOR:
1318 return PAGER_GetBkColor(hwnd);
1320 case PGM_GETBORDER:
1321 return PAGER_GetBorder(hwnd);
1323 case PGM_GETBUTTONSIZE:
1324 return PAGER_GetButtonSize(hwnd);
1326 case PGM_GETPOS:
1327 return PAGER_GetPos(hwnd);
1329 case PGM_GETBUTTONSTATE:
1330 return PAGER_GetButtonState (hwnd, wParam, lParam);
1332 /* case PGM_GETDROPTARGET: */
1334 case PGM_RECALCSIZE:
1335 return PAGER_RecalcSize(hwnd);
1337 case PGM_SETBKCOLOR:
1338 return PAGER_SetBkColor (hwnd, wParam, lParam);
1340 case PGM_SETBORDER:
1341 return PAGER_SetBorder (hwnd, wParam, lParam);
1343 case PGM_SETBUTTONSIZE:
1344 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1346 case PGM_SETCHILD:
1347 return PAGER_SetChild (hwnd, wParam, lParam);
1349 case PGM_SETPOS:
1350 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1352 case WM_CREATE:
1353 return PAGER_Create (hwnd, wParam, lParam);
1355 case WM_DESTROY:
1356 return PAGER_Destroy (hwnd, wParam, lParam);
1358 case WM_SIZE:
1359 return PAGER_Size (hwnd, wParam, lParam);
1361 case WM_NCPAINT:
1362 return PAGER_NCPaint (hwnd, wParam, lParam);
1364 case WM_WINDOWPOSCHANGING:
1365 return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1367 case WM_NCCALCSIZE:
1368 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1370 case WM_NCHITTEST:
1371 return PAGER_NCHitTest (hwnd, wParam, lParam);
1373 case WM_SETCURSOR:
1375 if (hwnd == (HWND)wParam)
1376 return PAGER_SetCursor(hwnd, wParam, lParam);
1377 else /* its for the child */
1378 return 0;
1381 case WM_MOUSEMOVE:
1382 if (infoPtr->bForward && infoPtr->hwndChild)
1383 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1384 return TRUE;
1386 case WM_MOUSELEAVE:
1387 return PAGER_MouseLeave (hwnd, wParam, lParam);
1389 case WM_LBUTTONDOWN:
1390 return PAGER_LButtonDown (hwnd, wParam, lParam);
1392 case WM_LBUTTONUP:
1393 return PAGER_LButtonUp (hwnd, wParam, lParam);
1395 case WM_ERASEBKGND:
1396 return PAGER_EraseBackground (hwnd, wParam, lParam);
1398 case WM_PAINT:
1399 return PAGER_Paint (hwnd, wParam);
1401 case WM_TIMER:
1402 /* if initial timer, kill it and start the repeat timer */
1403 if (wParam == TIMERID1)
1405 KillTimer(hwnd, TIMERID1);
1406 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1409 KillTimer(hwnd, TIMERID2);
1410 if (infoPtr->direction > 0)
1412 PAGER_Scroll(hwnd, infoPtr->direction);
1413 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1415 break;
1417 case WM_NOTIFY:
1418 case WM_COMMAND:
1419 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1421 default:
1422 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1425 return 0;
1429 VOID
1430 PAGER_Register (void)
1432 WNDCLASSA wndClass;
1434 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1435 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1436 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1437 wndClass.cbClsExtra = 0;
1438 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1439 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1440 wndClass.hbrBackground = 0;
1441 wndClass.lpszClassName = WC_PAGESCROLLERA;
1443 RegisterClassA (&wndClass);
1447 VOID
1448 PAGER_Unregister (void)
1450 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);