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
);