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 + infoPtr->nButtonSize;
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 + infoPtr->nButtonSize;
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);
610 SendMessageA(hwnd, WM_NCPAINT, (WPARAM)0, (LPARAM)0);
612 return (LRESULT)clrTemp;
617 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
619 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
620 INT nTemp = infoPtr->nBorder;
622 infoPtr->nBorder = (INT)lParam;
623 TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
625 PAGER_RecalcSize(hwnd);
627 return (LRESULT)nTemp;
632 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
634 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
635 INT nTemp = infoPtr->nButtonSize;
637 infoPtr->nButtonSize = (INT)lParam;
638 TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
640 PAGER_RecalcSize(hwnd);
642 return (LRESULT)nTemp;
647 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
649 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
651 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
653 if (infoPtr->hwndChild)
655 TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
657 if (PAGER_IsHorizontal(hwnd))
658 PAGER_SetFixedHeight(hwnd, infoPtr);
660 PAGER_SetFixedWidth(hwnd, infoPtr);
662 /* position child within the page scroller */
663 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
665 SWP_SHOWWINDOW | SWP_NOSIZE);
667 PAGER_SetPos(hwnd, 0, FALSE);
674 PAGER_Scroll(HWND hwnd, INT dir)
676 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
677 NMPGSCROLL nmpgScroll;
680 if (infoPtr->hwndChild)
682 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
683 nmpgScroll.hdr.hwndFrom = hwnd;
684 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
685 nmpgScroll.hdr.code = PGN_SCROLL;
687 GetWindowRect(hwnd, &rcWnd);
688 GetClientRect(hwnd, &nmpgScroll.rcParent);
689 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
690 nmpgScroll.iDir = dir;
692 if (PAGER_IsHorizontal(hwnd))
694 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
695 nmpgScroll.iXpos = infoPtr->nPos;
699 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
700 nmpgScroll.iYpos = infoPtr->nPos;
702 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
704 SendMessageA (hwnd, WM_NOTIFY,
705 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
707 TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
709 if (nmpgScroll.iScroll > 0)
711 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
712 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
714 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
720 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
723 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
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);
762 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
764 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
765 /* free pager info data */
766 COMCTL32_Free (infoPtr);
767 SetWindowLongA (hwnd, 0, 0);
772 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
774 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
775 LPRECT lpRect = (LPRECT)lParam;
777 * lParam points to a RECT struct. On entry, the struct
778 * contains the proposed wnd rectangle for the window.
779 * On exit, the struct should contain the screen
780 * coordinates of the corresponding window's client area.
783 if (PAGER_IsHorizontal(hwnd))
785 if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
786 lpRect->left += infoPtr->nButtonSize;
787 if (infoPtr->BRbtnState)
788 lpRect->right -= infoPtr->nButtonSize;
792 if (infoPtr->TLbtnState)
793 lpRect->top += infoPtr->nButtonSize;
794 if (infoPtr->BRbtnState)
795 lpRect->bottom -= infoPtr->nButtonSize;
798 TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
799 lpRect->right-lpRect->left,
800 lpRect->bottom-lpRect->top,
801 lpRect->left, lpRect->top);
807 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
809 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
810 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
811 RECT rcWindow, rcBottomRight, rcTopLeft;
813 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
815 if (dwStyle & WS_MINIMIZE)
818 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
820 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
823 GetWindowRect (hwnd, &rcWindow);
824 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
826 rcTopLeft = rcBottomRight = rcWindow;
829 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
830 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
834 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
835 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
838 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
839 bHorizontal, TRUE, infoPtr->TLbtnState);
840 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
841 bHorizontal, FALSE, infoPtr->BRbtnState);
843 ReleaseDC( hwnd, hdc );
848 PAGER_HitTest (HWND hwnd, LPPOINT pt)
850 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
852 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
854 GetClientRect (hwnd, &clientRect);
856 if (PtInRect(&clientRect, *pt))
858 /* TRACE("HTCLIENT\n"); */
862 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
866 if (pt->x < clientRect.left)
868 /* TRACE("HTLEFT\n"); */
874 if (pt->y < clientRect.top)
876 /* TRACE("HTTOP\n"); */
882 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
886 if (pt->x > clientRect.right)
888 /* TRACE("HTRIGHT\n"); */
894 if (pt->y > clientRect.bottom)
896 /* TRACE("HTBOTTOM\n"); */
902 /* TRACE("HTNOWHERE\n"); */
907 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
909 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
910 ScreenToClient (hwnd, &pt);
911 return PAGER_HitTest(hwnd, &pt);
915 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
917 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
918 BOOL notCaptured = FALSE;
920 switch(LOWORD(lParam))
924 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
925 infoPtr->TLbtnState = PGF_HOT;
929 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
930 infoPtr->BRbtnState = PGF_HOT;
938 TRACKMOUSEEVENT trackinfo;
940 TRACE("[%04x] SetCapture\n", hwnd);
943 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
944 trackinfo.dwFlags = TME_QUERY;
945 trackinfo.hwndTrack = hwnd;
946 trackinfo.dwHoverTime = HOVER_DEFAULT;
948 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
949 _TrackMouseEvent(&trackinfo);
951 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
952 if(!(trackinfo.dwFlags & TME_LEAVE)) {
953 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
955 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
956 /* and can properly deactivate the hot button */
957 _TrackMouseEvent(&trackinfo);
960 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
967 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
969 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
971 TRACE("[%04x] ReleaseCapture\n", hwnd);
974 /* Notify parent of released mouse capture */
977 ZeroMemory (&nmhdr, sizeof (NMHDR));
978 nmhdr.hwndFrom = hwnd;
979 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
980 nmhdr.code = NM_RELEASEDCAPTURE;
981 SendMessageA (GetParent(hwnd), WM_NOTIFY,
982 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
985 /* make HOT btns NORMAL and hide gray btns */
986 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
992 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
994 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
995 BOOL repaintBtns = FALSE;
996 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
999 TRACE("[%04x]\n", hwnd);
1001 hit = PAGER_HitTest(hwnd, &pt);
1003 /* put btn in DEPRESSED state */
1004 if (hit == HTLEFT || hit == HTTOP)
1006 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1007 infoPtr->TLbtnState = PGF_DEPRESSED;
1009 else if (hit == HTRIGHT || hit == HTBOTTOM)
1011 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1012 infoPtr->BRbtnState = PGF_DEPRESSED;
1016 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1021 TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1022 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1025 TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1026 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1029 TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1030 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1033 TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1034 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1044 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1046 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1047 TRACE("[%04x]\n", hwnd);
1049 /* make PRESSED btns NORMAL but don't hide gray btns */
1050 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1056 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1058 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1059 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1062 GetClientRect (hwnd, &rect);
1063 FillRect ((HDC)wParam, &rect, hBrush);
1065 /* background color of the child should be the same as the pager */
1066 if (infoPtr->hwndChild)
1068 GetClientRect (infoPtr->hwndChild, &rect);
1069 FillRect ((HDC)wParam, &rect, hBrush);
1072 DeleteObject (hBrush);
1078 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1080 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1082 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1083 TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1085 if (PAGER_IsHorizontal(hwnd))
1086 infoPtr->nHeight = HIWORD(lParam);
1088 infoPtr->nWidth = LOWORD(lParam);
1090 return PAGER_RecalcSize(hwnd);
1094 static LRESULT WINAPI
1095 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1097 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1099 if (!infoPtr && (uMsg != WM_CREATE))
1100 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1104 case PGM_FORWARDMOUSE:
1105 return PAGER_ForwardMouse (hwnd, wParam);
1107 case PGM_GETBKCOLOR:
1108 return PAGER_GetBkColor(hwnd);
1111 return PAGER_GetBorder(hwnd);
1113 case PGM_GETBUTTONSIZE:
1114 return PAGER_GetButtonSize(hwnd);
1117 return PAGER_GetPos(hwnd);
1119 case PGM_GETBUTTONSTATE:
1120 return PAGER_GetButtonState (hwnd, wParam, lParam);
1122 /* case PGM_GETDROPTARGET: */
1124 case PGM_RECALCSIZE:
1125 return PAGER_RecalcSize(hwnd);
1127 case PGM_SETBKCOLOR:
1128 return PAGER_SetBkColor (hwnd, wParam, lParam);
1131 return PAGER_SetBorder (hwnd, wParam, lParam);
1133 case PGM_SETBUTTONSIZE:
1134 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1137 return PAGER_SetChild (hwnd, wParam, lParam);
1140 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1143 return PAGER_Create (hwnd, wParam, lParam);
1146 return PAGER_Destroy (hwnd, wParam, lParam);
1149 return PAGER_Size (hwnd, wParam, lParam);
1152 return PAGER_NCPaint (hwnd, wParam, lParam);
1154 case WM_WINDOWPOSCHANGING:
1155 return PAGER_HandleWindowPosChanging (hwnd, (WINDOWPOS*)lParam);
1158 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1161 return PAGER_NCHitTest (hwnd, wParam, lParam);
1165 if (hwnd == (HWND)wParam)
1166 return PAGER_SetCursor(hwnd, wParam, lParam);
1167 else /* its for the child */
1172 if (infoPtr->bForward && infoPtr->hwndChild)
1173 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1177 return PAGER_MouseLeave (hwnd, wParam, lParam);
1179 case WM_LBUTTONDOWN:
1180 return PAGER_LButtonDown (hwnd, wParam, lParam);
1183 return PAGER_LButtonUp (hwnd, wParam, lParam);
1186 return PAGER_EraseBackground (hwnd, wParam, lParam);
1189 return PAGER_Paint (hwnd, wParam);
1193 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1196 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1204 PAGER_Register (void)
1208 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1209 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1210 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1211 wndClass.cbClsExtra = 0;
1212 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1213 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1214 wndClass.hbrBackground = 0;
1215 wndClass.lpszClassName = WC_PAGESCROLLERA;
1217 RegisterClassA (&wndClass);
1222 PAGER_Unregister (void)
1224 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);