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 */
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
47 /* the horizontal arrows are:
60 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
65 w = r.right - r.left + 1;
66 h = r.bottom - r.top + 1;
67 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
68 return; /* refuse to draw partial arrow */
70 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
73 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
74 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
75 MoveToEx (hdc, x, y, NULL);
76 LineTo (hdc, x--, y+5); y++;
77 MoveToEx (hdc, x, y, NULL);
78 LineTo (hdc, x--, y+3); y++;
79 MoveToEx (hdc, x, y, NULL);
84 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
85 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
86 MoveToEx (hdc, x, y, NULL);
87 LineTo (hdc, x++, y+5); y++;
88 MoveToEx (hdc, x, y, NULL);
89 LineTo (hdc, x++, y+3); y++;
90 MoveToEx (hdc, x, y, NULL);
94 SelectObject( hdc, hOldPen );
97 /* the vertical arrows are:
107 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
112 w = r.right - r.left + 1;
113 h = r.bottom - r.top + 1;
114 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
115 return; /* refuse to draw partial arrow */
117 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
120 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
121 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
122 MoveToEx (hdc, x, y, NULL);
123 LineTo (hdc, x+5, y--); x++;
124 MoveToEx (hdc, x, y, NULL);
125 LineTo (hdc, x+3, y--); x++;
126 MoveToEx (hdc, x, y, NULL);
127 LineTo (hdc, x+1, y);
131 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
132 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
133 MoveToEx (hdc, x, y, NULL);
134 LineTo (hdc, x+5, y++); x++;
135 MoveToEx (hdc, x, y, NULL);
136 LineTo (hdc, x+3, y++); x++;
137 MoveToEx (hdc, x, y, NULL);
138 LineTo (hdc, x+1, y);
141 SelectObject( hdc, hOldPen );
145 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
146 BOOL horz, BOOL topLeft, INT btnState)
148 HBRUSH hBrush, hOldBrush;
151 if (!btnState) /* PGF_INVISIBLE */
154 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
157 hBrush = CreateSolidBrush(clrBk);
158 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
160 FillRect(hdc, &rc, hBrush);
162 if (btnState == PGF_HOT)
164 rc.left++, rc.top++; rc.right++, rc.bottom++;
165 DrawEdge( hdc, &rc, EDGE_RAISED, BF_RECT);
167 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
169 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
170 rc.left--, rc.top--; rc.right--, rc.bottom--;
172 else if (btnState == PGF_NORMAL)
174 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
176 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
178 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
180 else if (btnState == PGF_DEPRESSED)
183 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
185 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
187 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);
205 rc.left--, rc.top--; rc.right--, rc.bottom--;
208 SelectObject( hdc, hOldBrush );
209 DeleteObject(hBrush);
212 /* << PAGER_GetDropTarget >> */
214 static inline LRESULT
215 PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
217 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
218 TRACE("[%04x]\n", hwnd);
220 infoPtr->bForward = (BOOL)wParam;
225 static inline LRESULT
226 PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
228 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
229 LRESULT btnState = PGF_INVISIBLE;
230 INT btn = (INT)lParam;
231 TRACE("[%04x]\n", hwnd);
233 if (btn == PGB_TOPORLEFT)
234 btnState = infoPtr->TLbtnState;
235 else if (btn == PGB_BOTTOMORRIGHT)
236 btnState = infoPtr->BRbtnState;
242 static inline LRESULT
243 PAGER_GetPos(HWND hwnd)
245 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
246 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nPos);
247 return (LRESULT)infoPtr->nPos;
250 static inline LRESULT
251 PAGER_GetButtonSize(HWND hwnd)
253 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
254 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nButtonSize);
255 return (LRESULT)infoPtr->nButtonSize;
258 static inline LRESULT
259 PAGER_GetBorder(HWND hwnd)
261 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
262 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nBorder);
263 return (LRESULT)infoPtr->nBorder;
266 static inline LRESULT
267 PAGER_GetBkColor(HWND hwnd)
269 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
270 TRACE("[%04x] returns %06lx\n", hwnd, infoPtr->clrBk);
271 return (LRESULT)infoPtr->clrBk;
275 PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
278 ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
279 nmpgcs.hdr.hwndFrom = hwnd;
280 nmpgcs.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
281 nmpgcs.hdr.code = PGN_CALCSIZE;
282 nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
283 nmpgcs.iWidth = getWidth ? *size : 0;
284 nmpgcs.iHeight = getWidth ? 0 : *size;
285 SendMessageA (hwnd, WM_NOTIFY,
286 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
288 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
290 TRACE("[%04x] PGN_CALCSIZE returns %s=%d\n", hwnd,
291 getWidth ? "width" : "height", *size);
295 PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
297 if (infoPtr->hwndChild)
300 int nPos = infoPtr->nPos;
302 /* compensate for a grayed btn, which will soon become invisible */
303 if (infoPtr->TLbtnState == PGF_GRAYED)
304 nPos += infoPtr->nButtonSize;
306 GetClientRect(hwnd, &rcClient);
308 if (PAGER_IsHorizontal(hwnd))
310 int wndSize = max(0, rcClient.right - rcClient.left);
311 if (infoPtr->nWidth < wndSize)
312 infoPtr->nWidth = wndSize;
314 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
315 infoPtr->nWidth, infoPtr->nHeight,
317 SetWindowPos(infoPtr->hwndChild, 0,
319 infoPtr->nWidth, infoPtr->nHeight,
324 int wndSize = max(0, rcClient.bottom - rcClient.top);
325 if (infoPtr->nHeight < wndSize)
326 infoPtr->nHeight = wndSize;
328 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
329 infoPtr->nWidth, infoPtr->nHeight,
331 SetWindowPos(infoPtr->hwndChild, 0,
333 infoPtr->nWidth, infoPtr->nHeight,
337 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
342 PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
346 if (infoPtr->hwndChild)
348 INT wndSize, childSize;
350 GetWindowRect(hwnd, &wndRect);
352 if (PAGER_IsHorizontal(hwnd))
354 wndSize = wndRect.right - wndRect.left;
355 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
356 childSize = infoPtr->nWidth;
360 wndSize = wndRect.bottom - wndRect.top;
361 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
362 childSize = infoPtr->nHeight;
365 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
366 if (childSize > wndSize)
367 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
370 TRACE("[%04x] returns %d\n", hwnd, scrollRange);
375 PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
376 BOOL* needsResize, BOOL* needsRepaint)
378 if (infoPtr->nPos > 0)
380 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
381 if (infoPtr->TLbtnState != PGF_DEPRESSED)
382 infoPtr->TLbtnState = PGF_NORMAL;
386 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
387 infoPtr->TLbtnState = PGF_GRAYED;
390 if (scrollRange <= 0)
392 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
393 infoPtr->TLbtnState = PGF_GRAYED;
394 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
395 infoPtr->BRbtnState = PGF_GRAYED;
397 else if (infoPtr->nPos < scrollRange)
399 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
400 if (infoPtr->BRbtnState != PGF_DEPRESSED)
401 infoPtr->BRbtnState = PGF_NORMAL;
405 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
406 infoPtr->BRbtnState = PGF_GRAYED;
412 PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
414 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
416 infoPtr->TLbtnState = PGF_NORMAL;
417 *needsRepaint = TRUE;
420 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
422 infoPtr->BRbtnState = PGF_NORMAL;
423 *needsRepaint = TRUE;
428 PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
430 if (infoPtr->TLbtnState == PGF_GRAYED)
432 infoPtr->TLbtnState = PGF_INVISIBLE;
436 if (infoPtr->BRbtnState == PGF_GRAYED)
438 infoPtr->BRbtnState = PGF_INVISIBLE;
444 PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
445 INT scrollRange, BOOL hideGrayBtns)
447 BOOL resizeClient = FALSE;
448 BOOL repaintBtns = FALSE;
451 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
453 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
456 PAGER_HideGrayBtns(infoPtr, &resizeClient);
458 if (resizeClient) /* initiate NCCalcSize to resize client wnd */
459 SetWindowPos(hwnd, 0,0,0,0,0,
460 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
461 SWP_NOZORDER | SWP_NOACTIVATE);
464 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
468 PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
470 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
471 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
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 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
483 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
484 PAGER_PositionChildWnd(hwnd, infoPtr);
490 PAGER_HandleWindowPosChanging(HWND hwnd, WINDOWPOS *winpos)
492 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
494 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
496 /* don't let the app resize the nonscrollable dimension of a control
497 * that was created with CCS_NORESIZE style
498 * (i.e. height for a horizontal pager, or width for a vertical one) */
500 if (PAGER_IsHorizontal(hwnd))
501 winpos->cy = infoPtr->nHeight;
503 winpos->cx = infoPtr->nWidth;
510 PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
512 /* Must set the non-scrollable dimension to be less than the full height/width
513 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
514 * size, and experimentation shows that affect is almost right. */
518 GetWindowRect(hwnd, &wndRect);
520 /* see what the app says for btn width */
521 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
523 if (infoPtr->bNoResize)
525 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
526 if (delta > infoPtr->nButtonSize)
527 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
529 infoPtr->nWidth += infoPtr->nButtonSize / 3;
532 h = wndRect.bottom - wndRect.top;
534 /* adjust non-scrollable dimension to fit the child */
535 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, h,
536 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
539 TRACE("[%04x] infoPtr->nWidth set to %d\n",
540 hwnd, infoPtr->nWidth);
544 PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
546 /* Must set the non-scrollable dimension to be less than the full height/width
547 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
548 * size, and experimentation shows that affect is almost right. */
552 GetWindowRect(hwnd, &wndRect);
554 /* see what the app says for btn height */
555 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
557 if (infoPtr->bNoResize)
559 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
560 if (delta > infoPtr->nButtonSize)
561 infoPtr->nHeight += 4 * infoPtr->nButtonSize / 3;
563 infoPtr->nHeight += infoPtr->nButtonSize / 3;
566 w = wndRect.right - wndRect.left;
568 /* adjust non-scrollable dimension to fit the child */
569 SetWindowPos(hwnd, 0, 0,0, w, infoPtr->nHeight,
570 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
572 TRACE("[%04x] infoPtr->nHeight set to %d\n",
573 hwnd, infoPtr->nHeight);
577 PAGER_RecalcSize(HWND hwnd)
579 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
581 TRACE("[%04x]\n", hwnd);
583 if (infoPtr->hwndChild)
585 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
587 if (scrollRange <= 0)
588 PAGER_SetPos(hwnd, 0, FALSE);
591 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
592 PAGER_PositionChildWnd(hwnd, infoPtr);
601 PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
603 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
604 COLORREF clrTemp = infoPtr->clrBk;
606 infoPtr->clrBk = (COLORREF)lParam;
607 TRACE("[%04x] %06lx\n", hwnd, infoPtr->clrBk);
609 PAGER_RecalcSize(hwnd);
611 return (LRESULT)clrTemp;
616 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
618 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
619 INT nTemp = infoPtr->nBorder;
621 infoPtr->nBorder = (INT)lParam;
622 TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
624 PAGER_RecalcSize(hwnd);
626 return (LRESULT)nTemp;
631 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
633 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
634 INT nTemp = infoPtr->nButtonSize;
636 infoPtr->nButtonSize = (INT)lParam;
637 TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
639 PAGER_RecalcSize(hwnd);
641 return (LRESULT)nTemp;
646 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
648 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
650 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
652 if (infoPtr->hwndChild)
654 TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
656 if (PAGER_IsHorizontal(hwnd))
657 PAGER_SetFixedHeight(hwnd, infoPtr);
659 PAGER_SetFixedWidth(hwnd, infoPtr);
661 /* position child within the page scroller */
662 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
664 SWP_SHOWWINDOW | SWP_NOSIZE);
666 PAGER_SetPos(hwnd, 0, FALSE);
673 PAGER_Scroll(HWND hwnd, INT dir)
675 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
676 NMPGSCROLL nmpgScroll;
678 if (infoPtr->hwndChild)
680 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
681 nmpgScroll.hdr.hwndFrom = hwnd;
682 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
683 nmpgScroll.hdr.code = PGN_SCROLL;
685 GetClientRect(hwnd, &nmpgScroll.rcParent);
686 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
687 nmpgScroll.iDir = dir;
689 if (PAGER_IsHorizontal(hwnd))
691 nmpgScroll.iScroll = nmpgScroll.rcParent.right -
692 nmpgScroll.rcParent.left;
693 nmpgScroll.iXpos = infoPtr->nPos;
697 nmpgScroll.iScroll = nmpgScroll.rcParent.bottom -
698 nmpgScroll.rcParent.top;
699 nmpgScroll.iYpos = infoPtr->nPos;
702 SendMessageA (hwnd, WM_NOTIFY,
703 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
705 TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
707 if (nmpgScroll.iScroll > 0)
709 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
710 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
712 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
718 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
721 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
723 dwStyle |= WS_CLIPCHILDREN;
725 /* allocate memory for info structure */
726 infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
727 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
729 /* set default settings */
730 infoPtr->hwndChild = (HWND)NULL;
731 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
732 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
733 infoPtr->nBorder = 0;
734 infoPtr->nButtonSize = 12;
737 infoPtr->nHeight = 0;
738 infoPtr->bForward = FALSE;
739 infoPtr->TLbtnState = PGF_INVISIBLE;
740 infoPtr->BRbtnState = PGF_INVISIBLE;
742 if (dwStyle & PGS_AUTOSCROLL)
743 FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
744 if (dwStyle & PGS_DRAGNDROP)
745 FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
747 * If neither horizontal nor vertical style specified, default to vertical.
748 * This is probably not necessary, since the style may be set later on as
749 * the control is initialized, but just in case it isn't, set it here.
751 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
754 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
760 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
762 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
763 /* free pager info data */
764 COMCTL32_Free (infoPtr);
765 SetWindowLongA (hwnd, 0, 0);
770 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
772 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
773 LPRECT lpRect = (LPRECT)lParam;
775 * lParam points to a RECT struct. On entry, the struct
776 * contains the proposed wnd rectangle for the window.
777 * On exit, the struct should contain the screen
778 * coordinates of the corresponding window's client area.
781 if (PAGER_IsHorizontal(hwnd))
783 if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
784 lpRect->left += infoPtr->nButtonSize;
785 if (infoPtr->BRbtnState)
786 lpRect->right -= infoPtr->nButtonSize;
790 if (infoPtr->TLbtnState)
791 lpRect->top += infoPtr->nButtonSize;
792 if (infoPtr->BRbtnState)
793 lpRect->bottom -= infoPtr->nButtonSize;
796 TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
797 lpRect->right-lpRect->left,
798 lpRect->bottom-lpRect->top,
799 lpRect->left, lpRect->top);
805 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
807 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
808 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
809 RECT rcWindow, rcBottomRight, rcTopLeft;
811 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
813 if (dwStyle & WS_MINIMIZE)
816 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
818 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
821 GetWindowRect (hwnd, &rcWindow);
822 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
824 rcTopLeft = rcBottomRight = rcWindow;
827 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
828 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
832 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
833 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
836 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
837 bHorizontal, TRUE, infoPtr->TLbtnState);
838 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
839 bHorizontal, FALSE, infoPtr->BRbtnState);
841 ReleaseDC( hwnd, hdc );
846 PAGER_HitTest (HWND hwnd, LPPOINT pt)
848 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
850 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
852 GetClientRect (hwnd, &clientRect);
854 if (PtInRect(&clientRect, *pt))
856 /* TRACE("HTCLIENT\n"); */
860 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
864 if (pt->x < clientRect.left)
866 /* TRACE("HTLEFT\n"); */
872 if (pt->y < clientRect.top)
874 /* TRACE("HTTOP\n"); */
880 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
884 if (pt->x > clientRect.right)
886 /* TRACE("HTRIGHT\n"); */
892 if (pt->y > clientRect.bottom)
894 /* TRACE("HTBOTTOM\n"); */
900 /* TRACE("HTNOWHERE\n"); */
905 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
907 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
908 ScreenToClient (hwnd, &pt);
909 return PAGER_HitTest(hwnd, &pt);
913 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
915 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
916 BOOL notCaptured = FALSE;
918 switch(LOWORD(lParam))
922 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
923 infoPtr->TLbtnState = PGF_HOT;
927 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
928 infoPtr->BRbtnState = PGF_HOT;
936 TRACKMOUSEEVENT trackinfo;
938 TRACE("[%04x] SetCapture\n", hwnd);
941 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
942 trackinfo.dwFlags = TME_QUERY;
943 trackinfo.hwndTrack = hwnd;
944 trackinfo.dwHoverTime = HOVER_DEFAULT;
946 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
947 _TrackMouseEvent(&trackinfo);
949 /* Make sure tracking is enabled so we recieve a WM_MOUSELEAVE message */
950 if(!(trackinfo.dwFlags & TME_LEAVE)) {
951 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
953 /* call TRACKMOUSEEVENT so we recieve a WM_MOUSELEAVE message */
954 /* and can properly deactivate the hot button */
955 _TrackMouseEvent(&trackinfo);
958 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
965 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
967 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
969 TRACE("[%04x] ReleaseCapture\n", hwnd);
972 /* Notify parent of released mouse capture */
973 if (infoPtr->hwndChild)
976 ZeroMemory (&nmhdr, sizeof (NMHDR));
977 nmhdr.hwndFrom = hwnd;
978 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
979 nmhdr.code = NM_RELEASEDCAPTURE;
980 SendMessageA (GetParent (infoPtr->hwndChild), WM_NOTIFY,
981 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
984 /* make HOT btns NORMAL and hide gray btns */
985 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
991 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
993 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
994 BOOL repaintBtns = FALSE;
995 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
998 TRACE("[%04x]\n", hwnd);
1000 hit = PAGER_HitTest(hwnd, &pt);
1002 /* put btn in DEPRESSED state */
1003 if (hit == HTLEFT || hit == HTTOP)
1005 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1006 infoPtr->TLbtnState = PGF_DEPRESSED;
1008 else if (hit == HTRIGHT || hit == HTBOTTOM)
1010 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1011 infoPtr->BRbtnState = PGF_DEPRESSED;
1015 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1020 TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1021 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1024 TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1025 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1028 TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1029 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1032 TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1033 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1043 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1045 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1046 TRACE("[%04x]\n", hwnd);
1048 /* make PRESSED btns NORMAL but don't hide gray btns */
1049 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1055 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1057 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1058 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1060 GetClientRect (hwnd, &rect);
1062 FillRect ((HDC)wParam, &rect, hBrush);
1063 DeleteObject (hBrush);
1069 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1071 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1073 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1074 TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1076 if (PAGER_IsHorizontal(hwnd))
1077 infoPtr->nHeight = HIWORD(lParam);
1079 infoPtr->nWidth = LOWORD(lParam);
1081 return PAGER_RecalcSize(hwnd);
1085 static LRESULT WINAPI
1086 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1088 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1090 if (!infoPtr && (uMsg != WM_CREATE))
1091 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1095 case PGM_FORWARDMOUSE:
1096 return PAGER_ForwardMouse (hwnd, wParam);
1098 case PGM_GETBKCOLOR:
1099 return PAGER_GetBkColor(hwnd);
1102 return PAGER_GetBorder(hwnd);
1104 case PGM_GETBUTTONSIZE:
1105 return PAGER_GetButtonSize(hwnd);
1108 return PAGER_GetPos(hwnd);
1110 case PGM_GETBUTTONSTATE:
1111 return PAGER_GetButtonState (hwnd, wParam, lParam);
1113 /* case PGM_GETDROPTARGET: */
1115 case PGM_RECALCSIZE:
1116 return PAGER_RecalcSize(hwnd);
1118 case PGM_SETBKCOLOR:
1119 return PAGER_SetBkColor (hwnd, wParam, lParam);
1122 return PAGER_SetBorder (hwnd, wParam, lParam);
1124 case PGM_SETBUTTONSIZE:
1125 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1128 return PAGER_SetChild (hwnd, wParam, lParam);
1131 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1134 return PAGER_Create (hwnd, wParam, lParam);
1137 return PAGER_Destroy (hwnd, wParam, lParam);
1140 return PAGER_Size (hwnd, wParam, lParam);
1143 return PAGER_NCPaint (hwnd, wParam, lParam);
1145 case WM_WINDOWPOSCHANGING:
1146 return PAGER_HandleWindowPosChanging (hwnd, (WINDOWPOS*)lParam);
1149 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1152 return PAGER_NCHitTest (hwnd, wParam, lParam);
1156 if (hwnd == (HWND)wParam)
1157 return PAGER_SetCursor(hwnd, wParam, lParam);
1158 else /* its for the child */
1163 if (infoPtr->bForward && infoPtr->hwndChild)
1164 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1168 return PAGER_MouseLeave (hwnd, wParam, lParam);
1170 case WM_LBUTTONDOWN:
1171 return PAGER_LButtonDown (hwnd, wParam, lParam);
1174 return PAGER_LButtonUp (hwnd, wParam, lParam);
1177 return PAGER_EraseBackground (hwnd, wParam, lParam);
1180 return PAGER_Paint (hwnd, wParam);
1184 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1187 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1195 PAGER_Register (void)
1199 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1200 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1201 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1202 wndClass.cbClsExtra = 0;
1203 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1204 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1205 wndClass.hbrBackground = 0;
1206 wndClass.lpszClassName = WC_PAGESCROLLERA;
1208 RegisterClassA (&wndClass);
1213 PAGER_Unregister (void)
1215 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);