Added tests for CryptSetProviderEx.
[wine/wine-kai.git] / dlls / comctl32 / pager.c
blob535d70819c2a790a5abf4ac2e403d3c40c71e502
1 /*
2 * Pager control
4 * Copyright 1998, 1999 Eric Kohl
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * NOTES
21 * Tested primarily with the controlspy Pager application.
22 * Susan Farley (susan@codeweavers.com)
24 * TODO:
25 * Implement repetitive button press.
26 * Adjust arrow size relative to size of button.
27 * Allow border size changes.
28 * Implement drag and drop style.
31 #include <stdarg.h>
32 #include <string.h>
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winnls.h"
38 #include "commctrl.h"
39 #include "comctl32.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(pager);
44 typedef struct
46 HWND hwndChild; /* handle of the contained wnd */
47 HWND hwndNotify; /* handle of the parent wnd */
48 BOOL bNoResize; /* set when created with CCS_NORESIZE */
49 COLORREF clrBk; /* background color */
50 INT nBorder; /* border size for the control */
51 INT nButtonSize;/* size of the pager btns */
52 INT nPos; /* scroll position */
53 INT nWidth; /* from child wnd's response to PGN_CALCSIZE */
54 INT nHeight; /* from child wnd's response to PGN_CALCSIZE */
55 BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */
56 BOOL bCapture; /* we have captured the mouse */
57 INT TLbtnState; /* state of top or left btn */
58 INT BRbtnState; /* state of bottom or right btn */
59 INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
60 } PAGER_INFO;
62 #define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
63 #define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
65 #define MIN_ARROW_WIDTH 8
66 #define MIN_ARROW_HEIGHT 5
68 #define TIMERID1 1
69 #define TIMERID2 2
70 #define INITIAL_DELAY 500
71 #define REPEAT_DELAY 50
73 /* the horizontal arrows are:
75 * 01234 01234
76 * 1 * *
77 * 2 ** **
78 * 3*** ***
79 * 4*** ***
80 * 5 ** **
81 * 6 * *
82 * 7
85 static void
86 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
88 INT x, y, w, h;
89 HPEN hPen, hOldPen;
91 w = r.right - r.left + 1;
92 h = r.bottom - r.top + 1;
93 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
94 return; /* refuse to draw partial arrow */
96 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
97 hOldPen = SelectObject ( hdc, hPen );
98 if (left)
100 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
101 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
102 MoveToEx (hdc, x, y, NULL);
103 LineTo (hdc, x--, y+5); y++;
104 MoveToEx (hdc, x, y, NULL);
105 LineTo (hdc, x--, y+3); y++;
106 MoveToEx (hdc, x, y, NULL);
107 LineTo (hdc, x, y+1);
109 else
111 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
112 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
113 MoveToEx (hdc, x, y, NULL);
114 LineTo (hdc, x++, y+5); y++;
115 MoveToEx (hdc, x, y, NULL);
116 LineTo (hdc, x++, y+3); y++;
117 MoveToEx (hdc, x, y, NULL);
118 LineTo (hdc, x, y+1);
121 SelectObject( hdc, hOldPen );
122 DeleteObject( hPen );
125 /* the vertical arrows are:
127 * 01234567 01234567
128 * 1****** **
129 * 2 **** ****
130 * 3 ** ******
134 static void
135 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
137 INT x, y, w, h;
138 HPEN hPen, hOldPen;
140 w = r.right - r.left + 1;
141 h = r.bottom - r.top + 1;
142 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
143 return; /* refuse to draw partial arrow */
145 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
146 hOldPen = SelectObject ( hdc, hPen );
147 if (up)
149 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
150 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
151 MoveToEx (hdc, x, y, NULL);
152 LineTo (hdc, x+5, y--); x++;
153 MoveToEx (hdc, x, y, NULL);
154 LineTo (hdc, x+3, y--); x++;
155 MoveToEx (hdc, x, y, NULL);
156 LineTo (hdc, x+1, y);
158 else
160 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
161 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
162 MoveToEx (hdc, x, y, NULL);
163 LineTo (hdc, x+5, y++); x++;
164 MoveToEx (hdc, x, y, NULL);
165 LineTo (hdc, x+3, y++); x++;
166 MoveToEx (hdc, x, y, NULL);
167 LineTo (hdc, x+1, y);
170 SelectObject( hdc, hOldPen );
171 DeleteObject( hPen );
174 static void
175 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
176 BOOL horz, BOOL topLeft, INT btnState)
178 HBRUSH hBrush, hOldBrush;
179 RECT rc = arrowRect;
181 if (!btnState) /* PGF_INVISIBLE */
182 return;
184 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
185 return;
187 hBrush = CreateSolidBrush(clrBk);
188 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
190 FillRect(hdc, &rc, hBrush);
192 if (btnState == PGF_HOT)
194 DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
195 if (horz)
196 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
197 else
198 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
200 else if (btnState == PGF_NORMAL)
202 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
203 if (horz)
204 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
205 else
206 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
208 else if (btnState == PGF_DEPRESSED)
210 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
211 if (horz)
212 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
213 else
214 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
216 else if (btnState == PGF_GRAYED)
218 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
219 if (horz)
221 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
222 rc.left++, rc.top++; rc.right++, rc.bottom++;
223 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
225 else
227 PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
228 rc.left++, rc.top++; rc.right++, rc.bottom++;
229 PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
233 SelectObject( hdc, hOldBrush );
234 DeleteObject(hBrush);
237 static void PAGER_CaptureandTrack(PAGER_INFO *infoPtr, HWND hwnd)
239 TRACKMOUSEEVENT trackinfo;
241 TRACE("[%p] SetCapture\n", hwnd);
242 SetCapture(hwnd);
243 infoPtr->bCapture = TRUE;
245 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
246 trackinfo.dwFlags = TME_QUERY;
247 trackinfo.hwndTrack = hwnd;
248 trackinfo.dwHoverTime = HOVER_DEFAULT;
250 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
251 _TrackMouseEvent(&trackinfo);
253 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
254 if(!(trackinfo.dwFlags & TME_LEAVE)) {
255 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
257 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
258 /* and can properly deactivate the hot button */
259 _TrackMouseEvent(&trackinfo);
264 /* << PAGER_GetDropTarget >> */
266 static inline LRESULT
267 PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
269 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
270 TRACE("[%p]\n", hwnd);
272 infoPtr->bForward = (BOOL)wParam;
274 return 0;
277 static inline LRESULT
278 PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
280 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
281 LRESULT btnState = PGF_INVISIBLE;
282 INT btn = (INT)lParam;
283 TRACE("[%p]\n", hwnd);
285 if (btn == PGB_TOPORLEFT)
286 btnState = infoPtr->TLbtnState;
287 else if (btn == PGB_BOTTOMORRIGHT)
288 btnState = infoPtr->BRbtnState;
290 return btnState;
294 static inline LRESULT
295 PAGER_GetPos(HWND hwnd)
297 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
298 TRACE("[%p] returns %d\n", hwnd, infoPtr->nPos);
299 return (LRESULT)infoPtr->nPos;
302 static inline LRESULT
303 PAGER_GetButtonSize(HWND hwnd)
305 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
306 TRACE("[%p] returns %d\n", hwnd, infoPtr->nButtonSize);
307 return (LRESULT)infoPtr->nButtonSize;
310 static inline LRESULT
311 PAGER_GetBorder(HWND hwnd)
313 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
314 TRACE("[%p] returns %d\n", hwnd, infoPtr->nBorder);
315 return (LRESULT)infoPtr->nBorder;
318 static inline LRESULT
319 PAGER_GetBkColor(HWND hwnd)
321 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
322 TRACE("[%p] returns %06lx\n", hwnd, infoPtr->clrBk);
323 return (LRESULT)infoPtr->clrBk;
326 static void
327 PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
329 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
330 NMPGCALCSIZE nmpgcs;
331 ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
332 nmpgcs.hdr.hwndFrom = hwnd;
333 nmpgcs.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
334 nmpgcs.hdr.code = PGN_CALCSIZE;
335 nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
336 nmpgcs.iWidth = getWidth ? *size : 0;
337 nmpgcs.iHeight = getWidth ? 0 : *size;
338 SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
339 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
341 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
343 TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", hwnd,
344 getWidth ? "width" : "height", *size);
347 static void
348 PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
350 if (infoPtr->hwndChild)
352 RECT rcClient;
353 int nPos = infoPtr->nPos;
355 /* compensate for a grayed btn, which will soon become invisible */
356 if (infoPtr->TLbtnState == PGF_GRAYED)
357 nPos += infoPtr->nButtonSize;
359 GetClientRect(hwnd, &rcClient);
361 if (PAGER_IsHorizontal(hwnd))
363 int wndSize = max(0, rcClient.right - rcClient.left);
364 if (infoPtr->nWidth < wndSize)
365 infoPtr->nWidth = wndSize;
367 TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
368 infoPtr->nWidth, infoPtr->nHeight,
369 -nPos, 0);
370 SetWindowPos(infoPtr->hwndChild, 0,
371 -nPos, 0,
372 infoPtr->nWidth, infoPtr->nHeight,
373 SWP_NOZORDER);
375 else
377 int wndSize = max(0, rcClient.bottom - rcClient.top);
378 if (infoPtr->nHeight < wndSize)
379 infoPtr->nHeight = wndSize;
381 TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
382 infoPtr->nWidth, infoPtr->nHeight,
383 0, -nPos);
384 SetWindowPos(infoPtr->hwndChild, 0,
385 0, -nPos,
386 infoPtr->nWidth, infoPtr->nHeight,
387 SWP_NOZORDER);
390 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
394 static INT
395 PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
397 INT scrollRange = 0;
399 if (infoPtr->hwndChild)
401 INT wndSize, childSize;
402 RECT wndRect;
403 GetWindowRect(hwnd, &wndRect);
405 if (PAGER_IsHorizontal(hwnd))
407 wndSize = wndRect.right - wndRect.left;
408 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
409 childSize = infoPtr->nWidth;
411 else
413 wndSize = wndRect.bottom - wndRect.top;
414 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
415 childSize = infoPtr->nHeight;
418 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
419 if (childSize > wndSize)
420 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
423 TRACE("[%p] returns %d\n", hwnd, scrollRange);
424 return scrollRange;
427 static void
428 PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
429 BOOL* needsResize, BOOL* needsRepaint)
431 if (infoPtr->nPos > 0)
433 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
434 if (infoPtr->TLbtnState != PGF_DEPRESSED)
435 infoPtr->TLbtnState = PGF_NORMAL;
437 else
439 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
440 infoPtr->TLbtnState = PGF_GRAYED;
443 if (scrollRange <= 0)
445 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
446 infoPtr->TLbtnState = PGF_GRAYED;
447 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
448 infoPtr->BRbtnState = PGF_GRAYED;
450 else if (infoPtr->nPos < scrollRange)
452 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
453 if (infoPtr->BRbtnState != PGF_DEPRESSED)
454 infoPtr->BRbtnState = PGF_NORMAL;
456 else
458 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
459 infoPtr->BRbtnState = PGF_GRAYED;
464 static void
465 PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
467 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
469 infoPtr->TLbtnState = PGF_NORMAL;
470 *needsRepaint = TRUE;
473 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
475 infoPtr->BRbtnState = PGF_NORMAL;
476 *needsRepaint = TRUE;
480 static void
481 PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
483 if (infoPtr->TLbtnState == PGF_GRAYED)
485 infoPtr->TLbtnState = PGF_INVISIBLE;
486 *needsResize = TRUE;
489 if (infoPtr->BRbtnState == PGF_GRAYED)
491 infoPtr->BRbtnState = PGF_INVISIBLE;
492 *needsResize = TRUE;
496 static void
497 PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
498 INT scrollRange, BOOL hideGrayBtns)
500 BOOL resizeClient = FALSE;
501 BOOL repaintBtns = FALSE;
503 if (scrollRange < 0)
504 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
505 else
506 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
508 if (hideGrayBtns)
509 PAGER_HideGrayBtns(infoPtr, &resizeClient);
511 if (resizeClient) /* initiate NCCalcSize to resize client wnd */ {
512 SetWindowPos(hwnd, 0,0,0,0,0,
513 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
514 SWP_NOZORDER | SWP_NOACTIVATE);
517 if (repaintBtns)
518 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
521 static LRESULT
522 PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
524 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
525 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
526 INT oldPos = infoPtr->nPos;
528 if ((scrollRange <= 0) || (newPos < 0))
529 infoPtr->nPos = 0;
530 else if (newPos > scrollRange)
531 infoPtr->nPos = scrollRange;
532 else
533 infoPtr->nPos = newPos;
535 TRACE("[%p] pos=%d, oldpos=%d\n", hwnd, infoPtr->nPos, oldPos);
537 if (infoPtr->nPos != oldPos)
539 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
540 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
541 PAGER_PositionChildWnd(hwnd, infoPtr);
544 return 0;
547 static LRESULT
548 PAGER_HandleWindowPosChanging(HWND hwnd, WPARAM wParam, WINDOWPOS *winpos)
550 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
552 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
554 /* don't let the app resize the nonscrollable dimension of a control
555 * that was created with CCS_NORESIZE style
556 * (i.e. height for a horizontal pager, or width for a vertical one) */
558 /* except if the current dimension is 0 and app is setting for
559 * first time, then save amount as dimension. - GA 8/01 */
561 if (PAGER_IsHorizontal(hwnd))
562 if (!infoPtr->nHeight && winpos->cy)
563 infoPtr->nHeight = winpos->cy;
564 else
565 winpos->cy = infoPtr->nHeight;
566 else
567 if (!infoPtr->nWidth && winpos->cx)
568 infoPtr->nWidth = winpos->cx;
569 else
570 winpos->cx = infoPtr->nWidth;
571 return 0;
574 DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, (LPARAM)winpos);
576 return 1;
579 static INT
580 PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
582 /* Must set the non-scrollable dimension to be less than the full height/width
583 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
584 * size, and experimentation shows that affect is almost right. */
586 RECT wndRect;
587 INT delta, h;
588 GetWindowRect(hwnd, &wndRect);
590 /* see what the app says for btn width */
591 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
593 if (infoPtr->bNoResize)
595 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
596 if (delta > infoPtr->nButtonSize)
597 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
598 else if (delta > 0)
599 infoPtr->nWidth += infoPtr->nButtonSize / 3;
602 h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
604 TRACE("[%p] infoPtr->nWidth set to %d\n",
605 hwnd, infoPtr->nWidth);
607 return h;
610 static INT
611 PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
613 /* Must set the non-scrollable dimension to be less than the full height/width
614 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
615 * size, and experimentation shows that affect is almost right. */
617 RECT wndRect;
618 INT delta, w;
619 GetWindowRect(hwnd, &wndRect);
621 /* see what the app says for btn height */
622 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
624 if (infoPtr->bNoResize)
626 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
627 if (delta > infoPtr->nButtonSize)
628 infoPtr->nHeight += infoPtr->nButtonSize;
629 else if (delta > 0)
630 infoPtr->nHeight += infoPtr->nButtonSize / 3;
633 w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
635 TRACE("[%p] infoPtr->nHeight set to %d\n",
636 hwnd, infoPtr->nHeight);
638 return w;
641 /******************************************************************
642 * For the PGM_RECALCSIZE message (but not the other uses in *
643 * this module), the native control does only the following: *
645 * if (some condition) *
646 * PostMessageA(hwnd, EM_FMTLINES, 0, 0); *
647 * return DefWindowProcA(hwnd, PGM_RECALCSIZE, 0, 0); *
649 * When we figure out what the "some condition" is we will *
650 * implement that for the message processing. *
651 ******************************************************************/
653 static LRESULT
654 PAGER_RecalcSize(HWND hwnd)
656 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
658 TRACE("[%p]\n", hwnd);
660 if (infoPtr->hwndChild)
662 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
664 if (scrollRange <= 0)
666 infoPtr->nPos = -1;
667 PAGER_SetPos(hwnd, 0, FALSE);
669 else
671 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
672 PAGER_PositionChildWnd(hwnd, infoPtr);
676 return 1;
680 static LRESULT
681 PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
683 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
684 COLORREF clrTemp = infoPtr->clrBk;
686 infoPtr->clrBk = (COLORREF)lParam;
687 TRACE("[%p] %06lx\n", hwnd, infoPtr->clrBk);
689 /* the native control seems to do things this way */
690 SetWindowPos(hwnd, 0,0,0,0,0,
691 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
692 SWP_NOZORDER | SWP_NOACTIVATE);
694 RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE);
696 return (LRESULT)clrTemp;
700 static LRESULT
701 PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
703 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
704 INT nTemp = infoPtr->nBorder;
706 infoPtr->nBorder = (INT)lParam;
707 TRACE("[%p] %d\n", hwnd, infoPtr->nBorder);
709 PAGER_RecalcSize(hwnd);
711 return (LRESULT)nTemp;
715 static LRESULT
716 PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
718 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
719 INT nTemp = infoPtr->nButtonSize;
721 infoPtr->nButtonSize = (INT)lParam;
722 TRACE("[%p] %d\n", hwnd, infoPtr->nButtonSize);
724 PAGER_RecalcSize(hwnd);
726 return (LRESULT)nTemp;
730 static LRESULT
731 PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
733 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
734 INT hw;
736 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
738 if (infoPtr->hwndChild)
740 TRACE("[%p] hwndChild=%p\n", hwnd, infoPtr->hwndChild);
742 if (PAGER_IsHorizontal(hwnd)) {
743 hw = PAGER_SetFixedHeight(hwnd, infoPtr);
744 /* adjust non-scrollable dimension to fit the child */
745 SetWindowPos(hwnd, 0, 0,0, hw, infoPtr->nHeight,
746 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
747 SWP_NOSIZE | SWP_NOACTIVATE);
749 else {
750 hw = PAGER_SetFixedWidth(hwnd, infoPtr);
751 /* adjust non-scrollable dimension to fit the child */
752 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, hw,
753 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
754 SWP_NOSIZE | SWP_NOACTIVATE);
757 /* position child within the page scroller */
758 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
759 0,0,0,0,
760 SWP_SHOWWINDOW | SWP_NOSIZE); /* native is 0 */
762 infoPtr->nPos = -1;
763 PAGER_SetPos(hwnd, 0, FALSE);
766 return 0;
769 static void
770 PAGER_Scroll(HWND hwnd, INT dir)
772 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
773 NMPGSCROLL nmpgScroll;
774 RECT rcWnd;
776 if (infoPtr->hwndChild)
778 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
779 nmpgScroll.hdr.hwndFrom = hwnd;
780 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
781 nmpgScroll.hdr.code = PGN_SCROLL;
783 GetWindowRect(hwnd, &rcWnd);
784 GetClientRect(hwnd, &nmpgScroll.rcParent);
785 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
786 nmpgScroll.iDir = dir;
788 if (PAGER_IsHorizontal(hwnd))
790 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
791 nmpgScroll.iXpos = infoPtr->nPos;
793 else
795 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
796 nmpgScroll.iYpos = infoPtr->nPos;
798 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
800 SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
801 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
803 TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
805 if (nmpgScroll.iScroll > 0)
807 infoPtr->direction = dir;
809 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
810 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
811 else
812 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
814 else
815 infoPtr->direction = -1;
819 static LRESULT
820 PAGER_FmtLines(HWND hwnd)
822 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
824 /* initiate NCCalcSize to resize client wnd and get size */
825 SetWindowPos(hwnd, 0, 0,0,0,0,
826 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
827 SWP_NOZORDER | SWP_NOACTIVATE);
829 SetWindowPos(infoPtr->hwndChild, 0,
830 0,0,infoPtr->nWidth,infoPtr->nHeight,
833 return DefWindowProcA (hwnd, EM_FMTLINES, 0, 0);
836 static LRESULT
837 PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
839 PAGER_INFO *infoPtr;
840 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
842 /* allocate memory for info structure */
843 infoPtr = (PAGER_INFO *)Alloc (sizeof(PAGER_INFO));
844 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
846 /* set default settings */
847 infoPtr->hwndChild = NULL;
848 infoPtr->hwndNotify = ((LPCREATESTRUCTW)lParam)->hwndParent;
849 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
850 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
851 infoPtr->nBorder = 0;
852 infoPtr->nButtonSize = 12;
853 infoPtr->nPos = 0;
854 infoPtr->nWidth = 0;
855 infoPtr->nHeight = 0;
856 infoPtr->bForward = FALSE;
857 infoPtr->bCapture = FALSE;
858 infoPtr->TLbtnState = PGF_INVISIBLE;
859 infoPtr->BRbtnState = PGF_INVISIBLE;
860 infoPtr->direction = -1;
862 if (dwStyle & PGS_DRAGNDROP)
863 FIXME("[%p] Drag and Drop style is not implemented yet.\n", hwnd);
865 * If neither horizontal nor vertical style specified, default to vertical.
866 * This is probably not necessary, since the style may be set later on as
867 * the control is initialized, but just in case it isn't, set it here.
869 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
871 dwStyle |= PGS_VERT;
872 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
875 return 0;
879 static LRESULT
880 PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
882 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
883 /* free pager info data */
884 Free (infoPtr);
885 SetWindowLongA (hwnd, 0, 0);
886 return 0;
889 static LRESULT
890 PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
892 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
893 LPRECT lpRect = (LPRECT)lParam;
894 RECT rcChildw, rcmyw, wnrc, ltrc, rbrc;
895 POINT cursor;
896 BOOL resizeClient = FALSE;
897 BOOL repaintBtns = FALSE;
898 INT scrollRange;
901 * lParam points to a RECT struct. On entry, the struct
902 * contains the proposed wnd rectangle for the window.
903 * On exit, the struct should contain the screen
904 * coordinates of the corresponding window's client area.
907 DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
909 TRACE("orig rect=(%ld,%ld)-(%ld,%ld)\n",
910 lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
912 if (PAGER_IsHorizontal(hwnd))
914 infoPtr->nWidth = lpRect->right - lpRect->left;
915 PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
916 GetWindowRect (infoPtr->hwndChild, &rcChildw);
917 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
918 GetCursorPos (&cursor);
919 GetWindowRect (hwnd, &rcmyw);
921 /* Reset buttons and hide any grey ones */
922 scrollRange = infoPtr->nWidth - (rcmyw.right - rcmyw.left);
924 TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%ld,%ld)-(%ld,%ld), cursor=(%ld,%ld)\n",
925 infoPtr->nPos, scrollRange, infoPtr->nHeight,
926 rcmyw.left, rcmyw.top,
927 rcmyw.right, rcmyw.bottom,
928 cursor.x, cursor.y);
929 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
930 PAGER_HideGrayBtns(infoPtr, &resizeClient);
932 if (PtInRect (&rcmyw, cursor)) {
933 GetWindowRect (hwnd, &wnrc);
934 ltrc = wnrc;
935 ltrc.right = ltrc.left + infoPtr->nButtonSize;
936 rbrc = wnrc;
937 rbrc.left = rbrc.right - infoPtr->nButtonSize;
938 TRACE("horz lt rect=(%ld,%ld)-(%ld,%ld), rb rect=(%ld,%ld)-(%ld,%ld)\n",
939 ltrc.left, ltrc.top, ltrc.right, ltrc.bottom,
940 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
941 if (PtInRect (&ltrc, cursor) && infoPtr->TLbtnState)
942 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
943 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
944 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
946 if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right))
947 lpRect->left += infoPtr->nButtonSize;
948 if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left))
949 lpRect->right -= infoPtr->nButtonSize;
951 else
953 /* native does: (from trace of IE4 opening "Favorites" frame)
954 * DefWindowProc
955 * WM_NOITFY PGN_CALCSIZE w/ dwFlag=2
956 * GetWindowRect (child, &rc)
957 * MapWindowPoints (0, syspager, &rc, 2)
958 * GetCursorPos( &cur )
959 * GetWindowRect (syspager, &rc2)
960 * PtInRect (&rc2, cur.x, cur.y) rtns 0
961 * returns with rect empty
963 infoPtr->nHeight = lpRect->bottom - lpRect->top;
964 PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
965 GetWindowRect (infoPtr->hwndChild, &rcChildw);
966 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
967 GetCursorPos (&cursor);
968 GetWindowRect (hwnd, &rcmyw);
970 /* Reset buttons and hide any grey ones */
971 scrollRange = infoPtr->nHeight - (rcmyw.bottom - rcmyw.top);
973 TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%ld,%ld)-(%ld,%ld), cursor=(%ld,%ld)\n",
974 infoPtr->nPos, scrollRange, infoPtr->nHeight,
975 rcmyw.left, rcmyw.top,
976 rcmyw.right, rcmyw.bottom,
977 cursor.x, cursor.y);
978 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
979 PAGER_HideGrayBtns(infoPtr, &resizeClient);
981 if (PtInRect (&rcmyw, cursor)) {
983 /* native does:
984 * GetWindowRect(pager, &rc)
985 * PtInRect(btn-left????, cur.x, cur.y)
986 * if true -> ???
987 * PtInRect(btn-right????, cur.x, cur.y)
988 * if true
989 * RedrawWindow(pager, 0, 0, 5)
990 * return TRUE
993 GetWindowRect (hwnd, &wnrc);
994 ltrc = wnrc;
995 ltrc.right = ltrc.left + infoPtr->nButtonSize;
996 rbrc = wnrc;
997 rbrc.left = rbrc.right - infoPtr->nButtonSize;
998 TRACE("vert lt rect=(%ld,%ld)-(%ld,%ld), rb rect=(%ld,%ld)-(%ld,%ld)\n",
999 ltrc.left, ltrc.top, ltrc.right, ltrc.bottom,
1000 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
1001 if (PtInRect (&ltrc, cursor) && infoPtr->TLbtnState)
1002 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
1003 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
1004 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
1006 if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom))
1007 lpRect->top += infoPtr->nButtonSize;
1008 if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top))
1009 lpRect->bottom -= infoPtr->nButtonSize;
1012 TRACE("[%p] client rect set to %ldx%ld at (%ld,%ld) BtnState[%d,%d]\n",
1013 hwnd, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top,
1014 lpRect->left, lpRect->top,
1015 infoPtr->TLbtnState, infoPtr->BRbtnState);
1017 return 0;
1020 static LRESULT
1021 PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
1023 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
1024 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1025 RECT rcWindow, rcBottomRight, rcTopLeft;
1026 HDC hdc;
1027 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1029 if (dwStyle & WS_MINIMIZE)
1030 return 0;
1032 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
1034 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
1035 return 0;
1037 GetWindowRect (hwnd, &rcWindow);
1038 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
1040 rcTopLeft = rcBottomRight = rcWindow;
1041 if (bHorizontal)
1043 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
1044 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
1046 else
1048 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
1049 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
1052 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
1053 bHorizontal, TRUE, infoPtr->TLbtnState);
1054 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
1055 bHorizontal, FALSE, infoPtr->BRbtnState);
1057 ReleaseDC( hwnd, hdc );
1058 return 0;
1061 static INT
1062 PAGER_HitTest (HWND hwnd, LPPOINT pt)
1064 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1065 RECT clientRect;
1066 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1068 GetClientRect (hwnd, &clientRect);
1070 if (PtInRect(&clientRect, *pt))
1072 TRACE("HTCLIENT\n");
1073 return HTCLIENT;
1076 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
1078 if (bHorizontal)
1080 if (pt->x < clientRect.left)
1082 TRACE("HTLEFT\n");
1083 return HTLEFT;
1086 else
1088 if (pt->y < clientRect.top)
1090 TRACE("HTTOP\n");
1091 return HTTOP;
1096 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
1098 if (bHorizontal)
1100 if (pt->x > clientRect.right)
1102 TRACE("HTRIGHT\n");
1103 return HTRIGHT;
1106 else
1108 if (pt->y > clientRect.bottom)
1110 TRACE("HTBOTTOM\n");
1111 return HTBOTTOM;
1116 TRACE("HTNOWHERE\n");
1117 return HTNOWHERE;
1120 static LRESULT
1121 PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1123 POINT pt;
1125 pt.x = (short)LOWORD(lParam);
1126 pt.y = (short)HIWORD(lParam);
1128 ScreenToClient (hwnd, &pt);
1129 return PAGER_HitTest(hwnd, &pt);
1132 static LRESULT
1133 PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1135 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1136 BOOL notCaptured = FALSE;
1138 switch(LOWORD(lParam))
1140 case HTLEFT:
1141 case HTTOP:
1142 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
1143 infoPtr->TLbtnState = PGF_HOT;
1144 break;
1145 case HTRIGHT:
1146 case HTBOTTOM:
1147 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
1148 infoPtr->BRbtnState = PGF_HOT;
1149 break;
1150 default:
1151 return FALSE;
1154 if (notCaptured)
1156 PAGER_CaptureandTrack(infoPtr, hwnd);
1158 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1161 return TRUE;
1164 static LRESULT
1165 PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1167 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1169 KillTimer (hwnd, TIMERID1);
1170 KillTimer (hwnd, TIMERID2);
1172 TRACE("[%p] ReleaseCapture\n", hwnd);
1173 ReleaseCapture();
1174 infoPtr->bCapture = FALSE;
1176 /* Notify parent of released mouse capture */
1178 NMHDR nmhdr;
1179 ZeroMemory (&nmhdr, sizeof (NMHDR));
1180 nmhdr.hwndFrom = hwnd;
1181 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1182 nmhdr.code = NM_RELEASEDCAPTURE;
1183 SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
1184 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1187 /* make HOT btns NORMAL and hide gray btns */
1188 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1190 return TRUE;
1193 static LRESULT
1194 PAGER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1196 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1197 POINT clpt, pt;
1198 RECT wnrect, TLbtnrect, BRbtnrect, *btnrect = NULL;
1199 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1200 BOOL topLeft = FALSE;
1201 INT btnstate = 0;
1202 INT hit;
1203 HDC hdc;
1205 pt.x = (short)LOWORD(lParam);
1206 pt.y = (short)HIWORD(lParam);
1208 TRACE("[%p] to (%ld,%ld)\n", hwnd, pt.x, pt.y);
1209 ClientToScreen(hwnd, &pt);
1210 GetWindowRect(hwnd, &wnrect);
1211 if (PtInRect(&wnrect, pt)) {
1212 TLbtnrect = wnrect;
1213 BRbtnrect = wnrect;
1214 if (dwStyle & PGS_HORZ) {
1215 TLbtnrect.right = TLbtnrect.left + infoPtr->nButtonSize;
1216 BRbtnrect.left = BRbtnrect.right - infoPtr->nButtonSize;
1218 else {
1219 TLbtnrect.bottom = TLbtnrect.top + infoPtr->nButtonSize;
1220 BRbtnrect.top = BRbtnrect.bottom - infoPtr->nButtonSize;
1223 clpt = pt;
1224 MapWindowPoints(0, hwnd, &clpt, 1);
1225 hit = PAGER_HitTest(hwnd, &clpt);
1226 if (hit == HTLEFT || hit == HTTOP) {
1227 topLeft = TRUE;
1228 btnrect = &TLbtnrect;
1229 infoPtr->TLbtnState = PGF_DEPRESSED;
1230 btnstate = infoPtr->TLbtnState;
1232 else if (hit == HTRIGHT || hit == HTBOTTOM) {
1233 topLeft = FALSE;
1234 btnrect = &BRbtnrect;
1235 infoPtr->BRbtnState = PGF_DEPRESSED;
1236 btnstate = infoPtr->BRbtnState;
1239 /* If in one of the buttons the capture and draw buttons */
1240 if (btnrect) {
1241 TRACE("[%p] draw btn (%ld,%ld)-(%ld,%ld), Capture %s, style %08lx\n",
1242 hwnd, btnrect->left, btnrect->top,
1243 btnrect->right, btnrect->bottom,
1244 (infoPtr->bCapture) ? "TRUE" : "FALSE",
1245 dwStyle);
1246 if (!infoPtr->bCapture)
1247 PAGER_CaptureandTrack(infoPtr, hwnd);
1248 if (dwStyle & PGS_AUTOSCROLL)
1249 SetTimer(hwnd, TIMERID1, 0x3e, 0);
1250 MapWindowPoints(0, hwnd, (LPPOINT)btnrect, 2);
1251 hdc = GetWindowDC(hwnd);
1252 /* OffsetRect(wnrect, 0 | 1, 0 | 1) */
1253 PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect,
1254 PAGER_IsHorizontal(hwnd), topLeft, btnstate);
1255 ReleaseDC(hwnd, hdc);
1256 return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
1260 /* If we think we are captured, then do release */
1261 if (infoPtr->bCapture) {
1262 infoPtr->bCapture = FALSE;
1264 if (GetCapture() == hwnd) {
1265 ReleaseCapture();
1266 /* Notify parent of released mouse capture */
1268 NMHDR nmhdr;
1269 ZeroMemory (&nmhdr, sizeof (NMHDR));
1270 nmhdr.hwndFrom = hwnd;
1271 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1272 nmhdr.code = NM_RELEASEDCAPTURE;
1273 SendMessageA (infoPtr->hwndNotify, WM_NOTIFY,
1274 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1277 if (IsWindow(hwnd))
1278 KillTimer(hwnd, TIMERID1);
1280 return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
1283 static LRESULT
1284 PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1286 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1287 BOOL repaintBtns = FALSE;
1288 POINT pt;
1289 INT hit;
1291 pt.x = (short)LOWORD(lParam);
1292 pt.y = (short)HIWORD(lParam);
1294 TRACE("[%p] at (%d,%d)\n", hwnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
1296 hit = PAGER_HitTest(hwnd, &pt);
1298 /* put btn in DEPRESSED state */
1299 if (hit == HTLEFT || hit == HTTOP)
1301 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1302 infoPtr->TLbtnState = PGF_DEPRESSED;
1303 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1305 else if (hit == HTRIGHT || hit == HTBOTTOM)
1307 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1308 infoPtr->BRbtnState = PGF_DEPRESSED;
1309 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1312 if (repaintBtns)
1313 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1315 switch(hit)
1317 case HTLEFT:
1318 TRACE("[%p] PGF_SCROLLLEFT\n", hwnd);
1319 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1320 break;
1321 case HTTOP:
1322 TRACE("[%p] PGF_SCROLLUP\n", hwnd);
1323 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1324 break;
1325 case HTRIGHT:
1326 TRACE("[%p] PGF_SCROLLRIGHT\n", hwnd);
1327 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1328 break;
1329 case HTBOTTOM:
1330 TRACE("[%p] PGF_SCROLLDOWN\n", hwnd);
1331 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1332 break;
1333 default:
1334 break;
1337 return TRUE;
1340 static LRESULT
1341 PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1343 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1344 TRACE("[%p]\n", hwnd);
1346 KillTimer (hwnd, TIMERID1);
1347 KillTimer (hwnd, TIMERID2);
1349 /* make PRESSED btns NORMAL but don't hide gray btns */
1350 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1352 return 0;
1355 static LRESULT
1356 PAGER_NCLButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1358 POINT pt;
1360 pt.x = (short)LOWORD(lParam);
1361 pt.y = (short)HIWORD(lParam);
1363 TRACE("[%p] at (%ld,%ld)\n", hwnd, pt.x, pt.y );
1364 MapWindowPoints(0, hwnd, &pt, 1);
1365 lParam = MAKELONG(pt.x, pt.y);
1366 return PAGER_LButtonDown (hwnd, wParam, lParam);
1369 static LRESULT
1370 PAGER_Timer (HWND hwnd, WPARAM wParam)
1372 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1373 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1374 INT dir;
1376 /* if initial timer, kill it and start the repeat timer */
1377 if (wParam == TIMERID1) {
1378 if (PAGER_IsHorizontal(hwnd)) {
1379 dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1380 PGF_SCROLLLEFT : PGF_SCROLLRIGHT;
1382 else {
1383 dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1384 PGF_SCROLLUP : PGF_SCROLLDOWN;
1386 TRACE("[%p] TIMERID1: style=%08lx, dir=%d\n", hwnd, dwStyle, dir);
1387 KillTimer(hwnd, TIMERID1);
1388 SetTimer(hwnd, TIMERID1, REPEAT_DELAY, 0);
1389 if (dwStyle & PGS_AUTOSCROLL) {
1390 PAGER_Scroll(hwnd, dir);
1391 SetWindowPos(hwnd, 0,0,0,0,0,
1392 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
1393 SWP_NOZORDER | SWP_NOACTIVATE);
1395 return 0;
1399 TRACE("[%p] TIMERID2: dir=%d\n", hwnd, infoPtr->direction);
1400 KillTimer(hwnd, TIMERID2);
1401 if (infoPtr->direction > 0) {
1402 PAGER_Scroll(hwnd, infoPtr->direction);
1403 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1405 return 0;
1408 static LRESULT
1409 PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1411 POINT pt, ptorig;
1412 HDC hdc = (HDC)wParam;
1413 HWND parent;
1415 /* native does:
1416 * parent = GetParent(pager)
1417 * pt.x=0; pt.y=0; ?????
1418 * MapWindowPoints(pager, parent, &pt, 1)
1419 * OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
1420 * SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
1421 * SetWindowOrgEx(hdc, 0, 0, 0)
1424 pt.x = 0;
1425 pt.y = 0;
1426 parent = GetParent(hwnd);
1427 MapWindowPoints(hwnd, parent, &pt, 1);
1428 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
1429 SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
1430 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
1433 #if 0
1434 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1435 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1436 RECT rect;
1438 GetClientRect (hwnd, &rect);
1439 FillRect ((HDC)wParam, &rect, hBrush);
1441 /* background color of the child should be the same as the pager */
1442 if (infoPtr->hwndChild)
1444 GetClientRect (infoPtr->hwndChild, &rect);
1445 FillRect ((HDC)wParam, &rect, hBrush);
1448 DeleteObject (hBrush);
1449 #endif
1451 return TRUE;
1455 static LRESULT
1456 PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1458 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1460 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1461 TRACE("[%p] %dx%d\n", hwnd, (short)LOWORD(lParam), (short)HIWORD(lParam));
1463 if (PAGER_IsHorizontal(hwnd))
1464 infoPtr->nHeight = (short)HIWORD(lParam);
1465 else
1466 infoPtr->nWidth = (short)LOWORD(lParam);
1468 return PAGER_RecalcSize(hwnd);
1472 static LRESULT WINAPI
1473 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1475 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1477 if (!infoPtr && (uMsg != WM_CREATE))
1478 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1480 switch (uMsg)
1482 case EM_FMTLINES:
1483 return PAGER_FmtLines(hwnd);
1485 case PGM_FORWARDMOUSE:
1486 return PAGER_ForwardMouse (hwnd, wParam);
1488 case PGM_GETBKCOLOR:
1489 return PAGER_GetBkColor(hwnd);
1491 case PGM_GETBORDER:
1492 return PAGER_GetBorder(hwnd);
1494 case PGM_GETBUTTONSIZE:
1495 return PAGER_GetButtonSize(hwnd);
1497 case PGM_GETPOS:
1498 return PAGER_GetPos(hwnd);
1500 case PGM_GETBUTTONSTATE:
1501 return PAGER_GetButtonState (hwnd, wParam, lParam);
1503 /* case PGM_GETDROPTARGET: */
1505 case PGM_RECALCSIZE:
1506 return PAGER_RecalcSize(hwnd);
1508 case PGM_SETBKCOLOR:
1509 return PAGER_SetBkColor (hwnd, wParam, lParam);
1511 case PGM_SETBORDER:
1512 return PAGER_SetBorder (hwnd, wParam, lParam);
1514 case PGM_SETBUTTONSIZE:
1515 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1517 case PGM_SETCHILD:
1518 return PAGER_SetChild (hwnd, wParam, lParam);
1520 case PGM_SETPOS:
1521 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1523 case WM_CREATE:
1524 return PAGER_Create (hwnd, wParam, lParam);
1526 case WM_DESTROY:
1527 return PAGER_Destroy (hwnd, wParam, lParam);
1529 case WM_SIZE:
1530 return PAGER_Size (hwnd, wParam, lParam);
1532 case WM_NCPAINT:
1533 return PAGER_NCPaint (hwnd, wParam, lParam);
1535 case WM_WINDOWPOSCHANGING:
1536 return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1538 case WM_NCCALCSIZE:
1539 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1541 case WM_NCHITTEST:
1542 return PAGER_NCHitTest (hwnd, wParam, lParam);
1544 case WM_SETCURSOR:
1546 if (hwnd == (HWND)wParam)
1547 return PAGER_SetCursor(hwnd, wParam, lParam);
1548 else /* its for the child */
1549 return 0;
1552 case WM_MOUSEMOVE:
1553 if (infoPtr->bForward && infoPtr->hwndChild)
1554 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1555 return PAGER_MouseMove (hwnd, wParam, lParam);
1557 case WM_MOUSELEAVE:
1558 return PAGER_MouseLeave (hwnd, wParam, lParam);
1560 case WM_NCLBUTTONDOWN:
1561 return PAGER_NCLButtonDown (hwnd, wParam, lParam);
1563 case WM_LBUTTONDOWN:
1564 return PAGER_LButtonDown (hwnd, wParam, lParam);
1566 case WM_NCLBUTTONUP:
1567 case WM_LBUTTONUP:
1568 return PAGER_LButtonUp (hwnd, wParam, lParam);
1570 case WM_ERASEBKGND:
1571 return PAGER_EraseBackground (hwnd, wParam, lParam);
1573 case WM_PAINT:
1574 return PAGER_Paint (hwnd, wParam);
1576 case WM_TIMER:
1577 return PAGER_Timer (hwnd, wParam);
1579 case WM_NOTIFY:
1580 case WM_COMMAND:
1581 return SendMessageA (infoPtr->hwndNotify, uMsg, wParam, lParam);
1583 default:
1584 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1587 return 0;
1591 VOID
1592 PAGER_Register (void)
1594 WNDCLASSA wndClass;
1596 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1597 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1598 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1599 wndClass.cbClsExtra = 0;
1600 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1601 wndClass.hCursor = LoadCursorA (0, (LPSTR)IDC_ARROW);
1602 wndClass.hbrBackground = 0;
1603 wndClass.lpszClassName = WC_PAGESCROLLERA;
1605 RegisterClassA (&wndClass);
1609 VOID
1610 PAGER_Unregister (void)
1612 UnregisterClassA (WC_PAGESCROLLERA, NULL);