4 * Copyright 1998, 1999 Eric Kohl
7 * Tested primarily with the controlspy Pager application.
8 * Susan Farley (susan@codeweavers.com)
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.
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(pager);
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) */
40 #define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
41 #define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
43 #define MIN_ARROW_WIDTH 8
44 #define MIN_ARROW_HEIGHT 5
48 #define INITIAL_DELAY 500
49 #define REPEAT_DELAY 50
51 /* the horizontal arrows are:
64 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
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 */
74 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
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);
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);
98 SelectObject( hdc, hOldPen );
101 /* the vertical arrows are:
111 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
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 */
121 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
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);
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);
145 SelectObject( hdc, hOldPen );
149 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
150 BOOL horz, BOOL topLeft, INT btnState)
152 HBRUSH hBrush, hOldBrush;
155 if (!btnState) /* PGF_INVISIBLE */
158 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
161 hBrush = CreateSolidBrush(clrBk);
162 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
164 FillRect(hdc, &rc, hBrush);
166 if (btnState == PGF_HOT)
168 DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
170 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
172 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
174 else if (btnState == PGF_NORMAL)
176 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
178 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
180 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
182 else if (btnState == PGF_DEPRESSED)
184 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
186 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
188 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
190 else if (btnState == PGF_GRAYED)
192 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
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);
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);
207 SelectObject( hdc, hOldBrush );
208 DeleteObject(hBrush);
211 /* << PAGER_GetDropTarget >> */
213 static inline LRESULT
214 PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
216 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
217 TRACE("[%04x]\n", hwnd);
219 infoPtr->bForward = (BOOL)wParam;
224 static inline LRESULT
225 PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
227 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
228 LRESULT btnState = PGF_INVISIBLE;
229 INT btn = (INT)lParam;
230 TRACE("[%04x]\n", hwnd);
232 if (btn == PGB_TOPORLEFT)
233 btnState = infoPtr->TLbtnState;
234 else if (btn == PGB_BOTTOMORRIGHT)
235 btnState = infoPtr->BRbtnState;
241 static inline LRESULT
242 PAGER_GetPos(HWND hwnd)
244 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
245 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nPos);
246 return (LRESULT)infoPtr->nPos;
249 static inline LRESULT
250 PAGER_GetButtonSize(HWND hwnd)
252 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
253 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nButtonSize);
254 return (LRESULT)infoPtr->nButtonSize;
257 static inline LRESULT
258 PAGER_GetBorder(HWND hwnd)
260 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
261 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nBorder);
262 return (LRESULT)infoPtr->nBorder;
265 static inline LRESULT
266 PAGER_GetBkColor(HWND hwnd)
268 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
269 TRACE("[%04x] returns %06lx\n", hwnd, infoPtr->clrBk);
270 return (LRESULT)infoPtr->clrBk;
274 PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
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 (hwnd, WM_NOTIFY,
285 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
287 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
289 TRACE("[%04x] PGN_CALCSIZE returns %s=%d\n", hwnd,
290 getWidth ? "width" : "height", *size);
294 PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
296 if (infoPtr->hwndChild)
299 int nPos = infoPtr->nPos;
301 /* compensate for a grayed btn, which will soon become invisible */
302 if (infoPtr->TLbtnState == PGF_GRAYED)
303 nPos += infoPtr->nButtonSize;
305 GetClientRect(hwnd, &rcClient);
307 if (PAGER_IsHorizontal(hwnd))
309 int wndSize = max(0, rcClient.right - rcClient.left);
310 if (infoPtr->nWidth < wndSize)
311 infoPtr->nWidth = wndSize;
313 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
314 infoPtr->nWidth, infoPtr->nHeight,
316 SetWindowPos(infoPtr->hwndChild, 0,
318 infoPtr->nWidth, infoPtr->nHeight,
323 int wndSize = max(0, rcClient.bottom - rcClient.top);
324 if (infoPtr->nHeight < wndSize)
325 infoPtr->nHeight = wndSize;
327 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
328 infoPtr->nWidth, infoPtr->nHeight,
330 SetWindowPos(infoPtr->hwndChild, 0,
332 infoPtr->nWidth, infoPtr->nHeight,
336 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
341 PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
345 if (infoPtr->hwndChild)
347 INT wndSize, childSize;
349 GetWindowRect(hwnd, &wndRect);
351 if (PAGER_IsHorizontal(hwnd))
353 wndSize = wndRect.right - wndRect.left;
354 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
355 childSize = infoPtr->nWidth;
359 wndSize = wndRect.bottom - wndRect.top;
360 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
361 childSize = infoPtr->nHeight;
364 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
365 if (childSize > wndSize)
366 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
369 TRACE("[%04x] returns %d\n", hwnd, scrollRange);
374 PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
375 BOOL* needsResize, BOOL* needsRepaint)
377 if (infoPtr->nPos > 0)
379 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
380 if (infoPtr->TLbtnState != PGF_DEPRESSED)
381 infoPtr->TLbtnState = PGF_NORMAL;
385 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
386 infoPtr->TLbtnState = PGF_GRAYED;
389 if (scrollRange <= 0)
391 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
392 infoPtr->TLbtnState = PGF_GRAYED;
393 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
394 infoPtr->BRbtnState = PGF_GRAYED;
396 else if (infoPtr->nPos < scrollRange)
398 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
399 if (infoPtr->BRbtnState != PGF_DEPRESSED)
400 infoPtr->BRbtnState = PGF_NORMAL;
404 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
405 infoPtr->BRbtnState = PGF_GRAYED;
411 PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
413 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
415 infoPtr->TLbtnState = PGF_NORMAL;
416 *needsRepaint = TRUE;
419 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
421 infoPtr->BRbtnState = PGF_NORMAL;
422 *needsRepaint = TRUE;
427 PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
429 if (infoPtr->TLbtnState == PGF_GRAYED)
431 infoPtr->TLbtnState = PGF_INVISIBLE;
435 if (infoPtr->BRbtnState == PGF_GRAYED)
437 infoPtr->BRbtnState = PGF_INVISIBLE;
443 PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
444 INT scrollRange, BOOL hideGrayBtns)
446 BOOL resizeClient = FALSE;
447 BOOL repaintBtns = FALSE;
450 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
452 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
455 PAGER_HideGrayBtns(infoPtr, &resizeClient);
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);
463 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
467 PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
469 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
470 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
471 INT oldPos = infoPtr->nPos;
473 if ((scrollRange <= 0) || (newPos < 0))
475 else if (newPos > scrollRange)
476 infoPtr->nPos = scrollRange;
478 infoPtr->nPos = newPos;
480 TRACE("[%04x] pos=%d\n", hwnd, infoPtr->nPos);
482 if (infoPtr->nPos != oldPos)
484 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
485 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
486 PAGER_PositionChildWnd(hwnd, infoPtr);
493 PAGER_HandleWindowPosChanging(HWND hwnd, WINDOWPOS *winpos)
495 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
497 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
499 /* don't let the app resize the nonscrollable dimension of a control
500 * that was created with CCS_NORESIZE style
501 * (i.e. height for a horizontal pager, or width for a vertical one) */
503 if (PAGER_IsHorizontal(hwnd))
504 winpos->cy = infoPtr->nHeight;
506 winpos->cx = infoPtr->nWidth;
513 PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
515 /* Must set the non-scrollable dimension to be less than the full height/width
516 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
517 * size, and experimentation shows that affect is almost right. */
521 GetWindowRect(hwnd, &wndRect);
523 /* see what the app says for btn width */
524 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
526 if (infoPtr->bNoResize)
528 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
529 if (delta > infoPtr->nButtonSize)
530 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
532 infoPtr->nWidth += infoPtr->nButtonSize / 3;
535 h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
537 /* adjust non-scrollable dimension to fit the child */
538 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, h,
539 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
542 TRACE("[%04x] infoPtr->nWidth set to %d\n",
543 hwnd, infoPtr->nWidth);
547 PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
549 /* Must set the non-scrollable dimension to be less than the full height/width
550 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
551 * size, and experimentation shows that affect is almost right. */
555 GetWindowRect(hwnd, &wndRect);
557 /* see what the app says for btn height */
558 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
560 if (infoPtr->bNoResize)
562 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
563 if (delta > infoPtr->nButtonSize)
564 infoPtr->nHeight += infoPtr->nButtonSize;
566 infoPtr->nHeight += infoPtr->nButtonSize / 3;
569 w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
571 /* adjust non-scrollable dimension to fit the child */
572 SetWindowPos(hwnd, 0, 0,0, w, infoPtr->nHeight,
573 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
575 TRACE("[%04x] infoPtr->nHeight set to %d\n",
576 hwnd, infoPtr->nHeight);
580 PAGER_RecalcSize(HWND hwnd)
582 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
584 TRACE("[%04x]\n", hwnd);
586 if (infoPtr->hwndChild)
588 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
590 if (scrollRange <= 0)
593 PAGER_SetPos(hwnd, 0, FALSE);
597 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
598 PAGER_PositionChildWnd(hwnd, infoPtr);
607 PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
609 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
610 COLORREF clrTemp = infoPtr->clrBk;
612 infoPtr->clrBk = (COLORREF)lParam;
613 TRACE("[%04x] %06lx\n", hwnd, infoPtr->clrBk);
615 PAGER_RecalcSize(hwnd);
616 SendMessageA(hwnd, WM_NCPAINT, (WPARAM)0, (LPARAM)0);
618 return (LRESULT)clrTemp;
623 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
625 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
626 INT nTemp = infoPtr->nBorder;
628 infoPtr->nBorder = (INT)lParam;
629 TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
631 PAGER_RecalcSize(hwnd);
633 return (LRESULT)nTemp;
638 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
640 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
641 INT nTemp = infoPtr->nButtonSize;
643 infoPtr->nButtonSize = (INT)lParam;
644 TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
646 PAGER_RecalcSize(hwnd);
648 return (LRESULT)nTemp;
653 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
655 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
657 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
659 if (infoPtr->hwndChild)
661 TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
663 if (PAGER_IsHorizontal(hwnd))
664 PAGER_SetFixedHeight(hwnd, infoPtr);
666 PAGER_SetFixedWidth(hwnd, infoPtr);
668 /* position child within the page scroller */
669 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
671 SWP_SHOWWINDOW | SWP_NOSIZE);
674 PAGER_SetPos(hwnd, 0, FALSE);
681 PAGER_Scroll(HWND hwnd, INT dir)
683 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
684 NMPGSCROLL nmpgScroll;
687 if (infoPtr->hwndChild)
689 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
690 nmpgScroll.hdr.hwndFrom = hwnd;
691 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
692 nmpgScroll.hdr.code = PGN_SCROLL;
694 GetWindowRect(hwnd, &rcWnd);
695 GetClientRect(hwnd, &nmpgScroll.rcParent);
696 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
697 nmpgScroll.iDir = dir;
699 if (PAGER_IsHorizontal(hwnd))
701 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
702 nmpgScroll.iXpos = infoPtr->nPos;
706 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
707 nmpgScroll.iYpos = infoPtr->nPos;
709 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
711 SendMessageA (hwnd, WM_NOTIFY,
712 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
714 TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
716 if (nmpgScroll.iScroll > 0)
718 infoPtr->direction = dir;
720 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
721 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
723 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
726 infoPtr->direction = -1;
731 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
734 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
736 /* allocate memory for info structure */
737 infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
738 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
740 /* set default settings */
741 infoPtr->hwndChild = (HWND)NULL;
742 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
743 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
744 infoPtr->nBorder = 0;
745 infoPtr->nButtonSize = 12;
748 infoPtr->nHeight = 0;
749 infoPtr->bForward = FALSE;
750 infoPtr->TLbtnState = PGF_INVISIBLE;
751 infoPtr->BRbtnState = PGF_INVISIBLE;
752 infoPtr->direction = -1;
754 if (dwStyle & PGS_AUTOSCROLL)
755 FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
756 if (dwStyle & PGS_DRAGNDROP)
757 FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
759 * If neither horizontal nor vertical style specified, default to vertical.
760 * This is probably not necessary, since the style may be set later on as
761 * the control is initialized, but just in case it isn't, set it here.
763 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
766 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
774 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
776 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
777 /* free pager info data */
778 COMCTL32_Free (infoPtr);
779 SetWindowLongA (hwnd, 0, 0);
784 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
786 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
787 LPRECT lpRect = (LPRECT)lParam;
789 * lParam points to a RECT struct. On entry, the struct
790 * contains the proposed wnd rectangle for the window.
791 * On exit, the struct should contain the screen
792 * coordinates of the corresponding window's client area.
795 if (PAGER_IsHorizontal(hwnd))
797 if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
798 lpRect->left += infoPtr->nButtonSize;
799 if (infoPtr->BRbtnState)
800 lpRect->right -= infoPtr->nButtonSize;
804 if (infoPtr->TLbtnState)
805 lpRect->top += infoPtr->nButtonSize;
806 if (infoPtr->BRbtnState)
807 lpRect->bottom -= infoPtr->nButtonSize;
810 TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
811 lpRect->right-lpRect->left,
812 lpRect->bottom-lpRect->top,
813 lpRect->left, lpRect->top);
819 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
821 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
822 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
823 RECT rcWindow, rcBottomRight, rcTopLeft;
825 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
827 if (dwStyle & WS_MINIMIZE)
830 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
832 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
835 GetWindowRect (hwnd, &rcWindow);
836 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
838 rcTopLeft = rcBottomRight = rcWindow;
841 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
842 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
846 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
847 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
850 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
851 bHorizontal, TRUE, infoPtr->TLbtnState);
852 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
853 bHorizontal, FALSE, infoPtr->BRbtnState);
855 ReleaseDC( hwnd, hdc );
860 PAGER_HitTest (HWND hwnd, LPPOINT pt)
862 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
864 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
866 GetClientRect (hwnd, &clientRect);
868 if (PtInRect(&clientRect, *pt))
870 /* TRACE("HTCLIENT\n"); */
874 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
878 if (pt->x < clientRect.left)
880 /* TRACE("HTLEFT\n"); */
886 if (pt->y < clientRect.top)
888 /* TRACE("HTTOP\n"); */
894 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
898 if (pt->x > clientRect.right)
900 /* TRACE("HTRIGHT\n"); */
906 if (pt->y > clientRect.bottom)
908 /* TRACE("HTBOTTOM\n"); */
914 /* TRACE("HTNOWHERE\n"); */
919 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
921 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
922 ScreenToClient (hwnd, &pt);
923 return PAGER_HitTest(hwnd, &pt);
927 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
929 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
930 BOOL notCaptured = FALSE;
932 switch(LOWORD(lParam))
936 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
937 infoPtr->TLbtnState = PGF_HOT;
941 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
942 infoPtr->BRbtnState = PGF_HOT;
950 TRACKMOUSEEVENT trackinfo;
952 TRACE("[%04x] SetCapture\n", hwnd);
955 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
956 trackinfo.dwFlags = TME_QUERY;
957 trackinfo.hwndTrack = hwnd;
958 trackinfo.dwHoverTime = HOVER_DEFAULT;
960 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
961 _TrackMouseEvent(&trackinfo);
963 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
964 if(!(trackinfo.dwFlags & TME_LEAVE)) {
965 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
967 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
968 /* and can properly deactivate the hot button */
969 _TrackMouseEvent(&trackinfo);
972 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
979 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
981 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
983 KillTimer (hwnd, TIMERID1);
984 KillTimer (hwnd, TIMERID2);
986 TRACE("[%04x] ReleaseCapture\n", hwnd);
989 /* Notify parent of released mouse capture */
992 ZeroMemory (&nmhdr, sizeof (NMHDR));
993 nmhdr.hwndFrom = hwnd;
994 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
995 nmhdr.code = NM_RELEASEDCAPTURE;
996 SendMessageA (GetParent(hwnd), WM_NOTIFY,
997 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1000 /* make HOT btns NORMAL and hide gray btns */
1001 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1007 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1009 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1010 BOOL repaintBtns = FALSE;
1011 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1014 TRACE("[%04x]\n", hwnd);
1016 hit = PAGER_HitTest(hwnd, &pt);
1018 /* put btn in DEPRESSED state */
1019 if (hit == HTLEFT || hit == HTTOP)
1021 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1022 infoPtr->TLbtnState = PGF_DEPRESSED;
1023 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1025 else if (hit == HTRIGHT || hit == HTBOTTOM)
1027 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1028 infoPtr->BRbtnState = PGF_DEPRESSED;
1029 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1033 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1038 TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1039 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1042 TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1043 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1046 TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1047 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1050 TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1051 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1061 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1063 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1064 TRACE("[%04x]\n", hwnd);
1066 KillTimer (hwnd, TIMERID1);
1067 KillTimer (hwnd, TIMERID2);
1069 /* make PRESSED btns NORMAL but don't hide gray btns */
1070 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1076 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1078 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1079 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1082 GetClientRect (hwnd, &rect);
1083 FillRect ((HDC)wParam, &rect, hBrush);
1085 /* background color of the child should be the same as the pager */
1086 if (infoPtr->hwndChild)
1088 GetClientRect (infoPtr->hwndChild, &rect);
1089 FillRect ((HDC)wParam, &rect, hBrush);
1092 DeleteObject (hBrush);
1098 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1100 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1102 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1103 TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1105 if (PAGER_IsHorizontal(hwnd))
1106 infoPtr->nHeight = HIWORD(lParam);
1108 infoPtr->nWidth = LOWORD(lParam);
1110 return PAGER_RecalcSize(hwnd);
1114 static LRESULT WINAPI
1115 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1117 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1119 if (!infoPtr && (uMsg != WM_CREATE))
1120 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1124 case PGM_FORWARDMOUSE:
1125 return PAGER_ForwardMouse (hwnd, wParam);
1127 case PGM_GETBKCOLOR:
1128 return PAGER_GetBkColor(hwnd);
1131 return PAGER_GetBorder(hwnd);
1133 case PGM_GETBUTTONSIZE:
1134 return PAGER_GetButtonSize(hwnd);
1137 return PAGER_GetPos(hwnd);
1139 case PGM_GETBUTTONSTATE:
1140 return PAGER_GetButtonState (hwnd, wParam, lParam);
1142 /* case PGM_GETDROPTARGET: */
1144 case PGM_RECALCSIZE:
1145 return PAGER_RecalcSize(hwnd);
1147 case PGM_SETBKCOLOR:
1148 return PAGER_SetBkColor (hwnd, wParam, lParam);
1151 return PAGER_SetBorder (hwnd, wParam, lParam);
1153 case PGM_SETBUTTONSIZE:
1154 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1157 return PAGER_SetChild (hwnd, wParam, lParam);
1160 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1163 return PAGER_Create (hwnd, wParam, lParam);
1166 return PAGER_Destroy (hwnd, wParam, lParam);
1169 return PAGER_Size (hwnd, wParam, lParam);
1172 return PAGER_NCPaint (hwnd, wParam, lParam);
1174 case WM_WINDOWPOSCHANGING:
1175 return PAGER_HandleWindowPosChanging (hwnd, (WINDOWPOS*)lParam);
1178 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1181 return PAGER_NCHitTest (hwnd, wParam, lParam);
1185 if (hwnd == (HWND)wParam)
1186 return PAGER_SetCursor(hwnd, wParam, lParam);
1187 else /* its for the child */
1192 if (infoPtr->bForward && infoPtr->hwndChild)
1193 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1197 return PAGER_MouseLeave (hwnd, wParam, lParam);
1199 case WM_LBUTTONDOWN:
1200 return PAGER_LButtonDown (hwnd, wParam, lParam);
1203 return PAGER_LButtonUp (hwnd, wParam, lParam);
1206 return PAGER_EraseBackground (hwnd, wParam, lParam);
1209 return PAGER_Paint (hwnd, wParam);
1212 /* if initial timer, kill it and start the repeat timer */
1213 if (wParam == TIMERID1)
1215 KillTimer(hwnd, TIMERID1);
1216 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1219 KillTimer(hwnd, TIMERID2);
1220 if (infoPtr->direction > 0)
1222 PAGER_Scroll(hwnd, infoPtr->direction);
1223 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1229 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1232 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1240 PAGER_Register (void)
1244 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1245 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1246 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1247 wndClass.cbClsExtra = 0;
1248 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1249 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1250 wndClass.hbrBackground = 0;
1251 wndClass.lpszClassName = WC_PAGESCROLLERA;
1253 RegisterClassA (&wndClass);
1258 PAGER_Unregister (void)
1260 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);