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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * This code was audited for completeness against the documented features
23 * of Comctl32.dll version 6.0 on Sep. 18, 2004, by Robert Shearman.
25 * Unless otherwise noted, we believe this code to be complete, as per
26 * the specification mentioned above.
27 * If you discover missing features or bugs please note them below.
30 * Implement repetitive button press.
31 * Adjust arrow size relative to size of button.
32 * Allow border size changes.
38 * WM_PRINT and/or WM_PRINTCLIENT
41 * Tested primarily with the controlspy Pager application.
42 * Susan Farley (susan@codeweavers.com)
44 * IMPLEMENTATION NOTES:
45 * This control uses WM_NCPAINT instead of WM_PAINT to paint itself
46 * as we need to scroll a child window. In order to do this we move
47 * the child window in the control's client area, using the clipping
48 * region that is automatically set around the client area. As the
49 * entire client area now consists of the child window, we must
50 * allocate space (WM_NCCALCSIZE) for the buttons and draw them as
51 * a non-client area (WM_NCPAINT).
52 * Robert Shearman <rob@codeweavers.com>
64 #include "wine/debug.h"
65 #include "wine/heap.h"
67 WINE_DEFAULT_DEBUG_CHANNEL(pager
);
71 HWND hwndSelf
; /* handle of the control wnd */
72 HWND hwndChild
; /* handle of the contained wnd */
73 HWND hwndNotify
; /* handle of the parent wnd */
74 BOOL bUnicode
; /* send notifications in Unicode */
75 DWORD dwStyle
; /* styles for this control */
76 COLORREF clrBk
; /* background color */
77 INT nBorder
; /* border size for the control */
78 INT nButtonSize
;/* size of the pager btns */
79 INT nPos
; /* scroll position */
80 INT nWidth
; /* from child wnd's response to PGN_CALCSIZE */
81 INT nHeight
; /* from child wnd's response to PGN_CALCSIZE */
82 BOOL bForward
; /* forward WM_MOUSEMOVE msgs to the contained wnd */
83 BOOL bCapture
; /* we have captured the mouse */
84 INT TLbtnState
; /* state of top or left btn */
85 INT BRbtnState
; /* state of bottom or right btn */
86 INT direction
; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
87 WCHAR
*pwszBuffer
;/* text buffer for converted notifications */
88 INT nBufferSize
;/* size of the above buffer */
93 #define INITIAL_DELAY 500
94 #define REPEAT_DELAY 50
96 /* Text field conversion behavior flags for PAGER_SendConvertedNotify() */
99 /* Convert Unicode text to ANSI for parent before sending. If not set, do nothing */
101 /* Convert ANSI text from parent back to Unicode for children */
102 CONVERT_RECEIVE
= 0x02,
103 /* Send empty text to parent if text is NULL. Original text pointer still remains NULL */
104 SEND_EMPTY_IF_NULL
= 0x04,
105 /* Set text to null after parent received the notification if the required mask is not set before sending notification */
106 SET_NULL_IF_NO_MASK
= 0x08,
107 /* Zero out the text buffer before sending it to parent */
112 PAGER_GetButtonRects(const PAGER_INFO
* infoPtr
, RECT
* prcTopLeft
, RECT
* prcBottomRight
, BOOL bClientCoords
)
115 GetWindowRect (infoPtr
->hwndSelf
, &rcWindow
);
118 MapWindowPoints( 0, infoPtr
->hwndSelf
, (POINT
*)&rcWindow
, 2 );
120 OffsetRect(&rcWindow
, -rcWindow
.left
, -rcWindow
.top
);
122 *prcTopLeft
= *prcBottomRight
= rcWindow
;
123 if (infoPtr
->dwStyle
& PGS_HORZ
)
125 prcTopLeft
->right
= prcTopLeft
->left
+ infoPtr
->nButtonSize
;
126 prcBottomRight
->left
= prcBottomRight
->right
- infoPtr
->nButtonSize
;
130 prcTopLeft
->bottom
= prcTopLeft
->top
+ infoPtr
->nButtonSize
;
131 prcBottomRight
->top
= prcBottomRight
->bottom
- infoPtr
->nButtonSize
;
136 PAGER_DrawButton(HDC hdc
, COLORREF clrBk
, RECT rc
,
137 BOOL horz
, BOOL topLeft
, INT btnState
)
141 TRACE("rc = %s, btnState = %d\n", wine_dbgstr_rect(&rc
), btnState
);
143 if (btnState
== PGF_INVISIBLE
)
146 if ((rc
.right
- rc
.left
<= 0) || (rc
.bottom
- rc
.top
<= 0))
150 flags
= topLeft
? DFCS_SCROLLLEFT
: DFCS_SCROLLRIGHT
;
152 flags
= topLeft
? DFCS_SCROLLUP
: DFCS_SCROLLDOWN
;
162 flags
|= DFCS_PUSHED
;
165 flags
|= DFCS_INACTIVE
| DFCS_FLAT
;
168 DrawFrameControl( hdc
, &rc
, DFC_SCROLL
, flags
);
171 /* << PAGER_GetDropTarget >> */
173 static inline LRESULT
174 PAGER_ForwardMouse (PAGER_INFO
* infoPtr
, BOOL bFwd
)
176 TRACE("[%p]\n", infoPtr
->hwndSelf
);
178 infoPtr
->bForward
= bFwd
;
183 static inline LRESULT
184 PAGER_GetButtonState (const PAGER_INFO
* infoPtr
, INT btn
)
186 LRESULT btnState
= PGF_INVISIBLE
;
187 TRACE("[%p]\n", infoPtr
->hwndSelf
);
189 if (btn
== PGB_TOPORLEFT
)
190 btnState
= infoPtr
->TLbtnState
;
191 else if (btn
== PGB_BOTTOMORRIGHT
)
192 btnState
= infoPtr
->BRbtnState
;
199 PAGER_GetPos(const PAGER_INFO
*infoPtr
)
201 TRACE("[%p] returns %d\n", infoPtr
->hwndSelf
, infoPtr
->nPos
);
202 return infoPtr
->nPos
;
206 PAGER_GetButtonSize(const PAGER_INFO
*infoPtr
)
208 TRACE("[%p] returns %d\n", infoPtr
->hwndSelf
, infoPtr
->nButtonSize
);
209 return infoPtr
->nButtonSize
;
213 PAGER_GetBorder(const PAGER_INFO
*infoPtr
)
215 TRACE("[%p] returns %d\n", infoPtr
->hwndSelf
, infoPtr
->nBorder
);
216 return infoPtr
->nBorder
;
219 static inline COLORREF
220 PAGER_GetBkColor(const PAGER_INFO
*infoPtr
)
222 TRACE("[%p] returns %06x\n", infoPtr
->hwndSelf
, infoPtr
->clrBk
);
223 return infoPtr
->clrBk
;
227 PAGER_CalcSize( PAGER_INFO
*infoPtr
)
230 ZeroMemory (&nmpgcs
, sizeof (NMPGCALCSIZE
));
231 nmpgcs
.hdr
.hwndFrom
= infoPtr
->hwndSelf
;
232 nmpgcs
.hdr
.idFrom
= GetWindowLongPtrW (infoPtr
->hwndSelf
, GWLP_ID
);
233 nmpgcs
.hdr
.code
= PGN_CALCSIZE
;
234 nmpgcs
.dwFlag
= (infoPtr
->dwStyle
& PGS_HORZ
) ? PGF_CALCWIDTH
: PGF_CALCHEIGHT
;
235 nmpgcs
.iWidth
= infoPtr
->nWidth
;
236 nmpgcs
.iHeight
= infoPtr
->nHeight
;
237 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
, nmpgcs
.hdr
.idFrom
, (LPARAM
)&nmpgcs
);
239 if (infoPtr
->dwStyle
& PGS_HORZ
)
240 infoPtr
->nWidth
= nmpgcs
.iWidth
;
242 infoPtr
->nHeight
= nmpgcs
.iHeight
;
244 TRACE("[%p] PGN_CALCSIZE returns %dx%d\n", infoPtr
->hwndSelf
, nmpgcs
.iWidth
, nmpgcs
.iHeight
);
248 PAGER_PositionChildWnd(PAGER_INFO
* infoPtr
)
250 if (infoPtr
->hwndChild
)
253 int nPos
= infoPtr
->nPos
;
255 /* compensate for a grayed btn, which will soon become invisible */
256 if (infoPtr
->TLbtnState
== PGF_GRAYED
)
257 nPos
+= infoPtr
->nButtonSize
;
259 GetClientRect(infoPtr
->hwndSelf
, &rcClient
);
261 if (infoPtr
->dwStyle
& PGS_HORZ
)
263 int wndSize
= max(0, rcClient
.right
- rcClient
.left
);
264 if (infoPtr
->nWidth
< wndSize
)
265 infoPtr
->nWidth
= wndSize
;
267 TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr
->hwndSelf
,
268 infoPtr
->nWidth
, infoPtr
->nHeight
,
270 SetWindowPos(infoPtr
->hwndChild
, HWND_TOP
,
272 infoPtr
->nWidth
, infoPtr
->nHeight
, 0);
276 int wndSize
= max(0, rcClient
.bottom
- rcClient
.top
);
277 if (infoPtr
->nHeight
< wndSize
)
278 infoPtr
->nHeight
= wndSize
;
280 TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr
->hwndSelf
,
281 infoPtr
->nWidth
, infoPtr
->nHeight
,
283 SetWindowPos(infoPtr
->hwndChild
, HWND_TOP
,
285 infoPtr
->nWidth
, infoPtr
->nHeight
, 0);
288 InvalidateRect(infoPtr
->hwndChild
, NULL
, TRUE
);
293 PAGER_GetScrollRange(PAGER_INFO
* infoPtr
, BOOL calc_size
)
297 if (infoPtr
->hwndChild
)
299 INT wndSize
, childSize
;
301 GetWindowRect(infoPtr
->hwndSelf
, &wndRect
);
304 PAGER_CalcSize(infoPtr
);
305 if (infoPtr
->dwStyle
& PGS_HORZ
)
307 wndSize
= wndRect
.right
- wndRect
.left
;
308 childSize
= infoPtr
->nWidth
;
312 wndSize
= wndRect
.bottom
- wndRect
.top
;
313 childSize
= infoPtr
->nHeight
;
316 TRACE("childSize = %d, wndSize = %d\n", childSize
, wndSize
);
317 if (childSize
> wndSize
)
318 scrollRange
= childSize
- wndSize
+ infoPtr
->nButtonSize
;
321 TRACE("[%p] returns %d\n", infoPtr
->hwndSelf
, scrollRange
);
326 PAGER_UpdateBtns(PAGER_INFO
*infoPtr
, INT scrollRange
, BOOL hideGrayBtns
)
330 INT oldTLbtnState
= infoPtr
->TLbtnState
;
331 INT oldBRbtnState
= infoPtr
->BRbtnState
;
333 RECT rcTopLeft
, rcBottomRight
;
335 /* get button rects */
336 PAGER_GetButtonRects(infoPtr
, &rcTopLeft
, &rcBottomRight
, TRUE
);
339 ScreenToClient( infoPtr
->hwndSelf
, &pt
);
341 /* update states based on scroll position */
342 if (infoPtr
->nPos
> 0)
344 if (infoPtr
->TLbtnState
== PGF_INVISIBLE
|| infoPtr
->TLbtnState
== PGF_GRAYED
)
345 infoPtr
->TLbtnState
= PGF_NORMAL
;
347 else if (!hideGrayBtns
&& PtInRect(&rcTopLeft
, pt
))
348 infoPtr
->TLbtnState
= PGF_GRAYED
;
350 infoPtr
->TLbtnState
= PGF_INVISIBLE
;
352 if (scrollRange
<= 0)
354 infoPtr
->TLbtnState
= PGF_INVISIBLE
;
355 infoPtr
->BRbtnState
= PGF_INVISIBLE
;
357 else if (infoPtr
->nPos
< scrollRange
)
359 if (infoPtr
->BRbtnState
== PGF_INVISIBLE
|| infoPtr
->BRbtnState
== PGF_GRAYED
)
360 infoPtr
->BRbtnState
= PGF_NORMAL
;
362 else if (!hideGrayBtns
&& PtInRect(&rcBottomRight
, pt
))
363 infoPtr
->BRbtnState
= PGF_GRAYED
;
365 infoPtr
->BRbtnState
= PGF_INVISIBLE
;
367 /* only need to resize when entering or leaving PGF_INVISIBLE state */
369 ((oldTLbtnState
== PGF_INVISIBLE
) != (infoPtr
->TLbtnState
== PGF_INVISIBLE
)) ||
370 ((oldBRbtnState
== PGF_INVISIBLE
) != (infoPtr
->BRbtnState
== PGF_INVISIBLE
));
371 /* initiate NCCalcSize to resize client wnd if necessary */
373 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
374 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
375 SWP_NOZORDER
| SWP_NOACTIVATE
);
377 /* repaint when changing any state */
378 repaintBtns
= (oldTLbtnState
!= infoPtr
->TLbtnState
) ||
379 (oldBRbtnState
!= infoPtr
->BRbtnState
);
381 SendMessageW(infoPtr
->hwndSelf
, WM_NCPAINT
, 0, 0);
385 PAGER_SetPos(PAGER_INFO
* infoPtr
, INT newPos
, BOOL fromBtnPress
, BOOL calc_size
)
387 INT scrollRange
= PAGER_GetScrollRange(infoPtr
, calc_size
);
388 INT oldPos
= infoPtr
->nPos
;
390 if ((scrollRange
<= 0) || (newPos
< 0))
392 else if (newPos
> scrollRange
)
393 infoPtr
->nPos
= scrollRange
;
395 infoPtr
->nPos
= newPos
;
397 TRACE("[%p] pos=%d, oldpos=%d\n", infoPtr
->hwndSelf
, infoPtr
->nPos
, oldPos
);
399 if (infoPtr
->nPos
!= oldPos
)
401 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
402 PAGER_UpdateBtns(infoPtr
, scrollRange
, !fromBtnPress
);
403 PAGER_PositionChildWnd(infoPtr
);
409 /******************************************************************
410 * For the PGM_RECALCSIZE message (but not the other uses in *
411 * this module), the native control does only the following: *
413 * if (some condition) *
414 * PostMessageW(hwnd, EM_FMTLINES, 0, 0); *
415 * return DefWindowProcW(hwnd, PGM_RECALCSIZE, 0, 0); *
417 * When we figure out what the "some condition" is we will *
418 * implement that for the message processing. *
419 ******************************************************************/
422 PAGER_RecalcSize(PAGER_INFO
*infoPtr
)
424 TRACE("[%p]\n", infoPtr
->hwndSelf
);
426 if (infoPtr
->hwndChild
)
428 INT scrollRange
= PAGER_GetScrollRange(infoPtr
, TRUE
);
430 if (scrollRange
<= 0)
433 PAGER_SetPos(infoPtr
, 0, FALSE
, TRUE
);
436 PAGER_PositionChildWnd(infoPtr
);
444 PAGER_SetBkColor (PAGER_INFO
* infoPtr
, COLORREF clrBk
)
446 COLORREF clrTemp
= infoPtr
->clrBk
;
448 infoPtr
->clrBk
= clrBk
;
449 TRACE("[%p] %06x\n", infoPtr
->hwndSelf
, infoPtr
->clrBk
);
451 /* the native control seems to do things this way */
452 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
453 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
454 SWP_NOZORDER
| SWP_NOACTIVATE
);
456 RedrawWindow(infoPtr
->hwndSelf
, 0, 0, RDW_ERASE
| RDW_INVALIDATE
);
463 PAGER_SetBorder (PAGER_INFO
* infoPtr
, INT iBorder
)
465 INT nTemp
= infoPtr
->nBorder
;
467 infoPtr
->nBorder
= iBorder
;
468 TRACE("[%p] %d\n", infoPtr
->hwndSelf
, infoPtr
->nBorder
);
470 PAGER_RecalcSize(infoPtr
);
477 PAGER_SetButtonSize (PAGER_INFO
* infoPtr
, INT iButtonSize
)
479 INT nTemp
= infoPtr
->nButtonSize
;
481 infoPtr
->nButtonSize
= iButtonSize
;
482 TRACE("[%p] %d\n", infoPtr
->hwndSelf
, infoPtr
->nButtonSize
);
484 PAGER_RecalcSize(infoPtr
);
491 PAGER_SetChild (PAGER_INFO
* infoPtr
, HWND hwndChild
)
493 infoPtr
->hwndChild
= IsWindow (hwndChild
) ? hwndChild
: 0;
495 if (infoPtr
->hwndChild
)
497 TRACE("[%p] hwndChild=%p\n", infoPtr
->hwndSelf
, infoPtr
->hwndChild
);
499 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
500 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
503 PAGER_SetPos(infoPtr
, 0, FALSE
, FALSE
);
510 PAGER_Scroll(PAGER_INFO
* infoPtr
, INT dir
)
512 NMPGSCROLL nmpgScroll
;
515 if (infoPtr
->hwndChild
)
517 ZeroMemory (&nmpgScroll
, sizeof (NMPGSCROLL
));
518 nmpgScroll
.hdr
.hwndFrom
= infoPtr
->hwndSelf
;
519 nmpgScroll
.hdr
.idFrom
= GetWindowLongPtrW (infoPtr
->hwndSelf
, GWLP_ID
);
520 nmpgScroll
.hdr
.code
= PGN_SCROLL
;
522 GetWindowRect(infoPtr
->hwndSelf
, &rcWnd
);
523 GetClientRect(infoPtr
->hwndSelf
, &nmpgScroll
.rcParent
);
524 nmpgScroll
.iXpos
= nmpgScroll
.iYpos
= 0;
525 nmpgScroll
.iDir
= dir
;
527 if (infoPtr
->dwStyle
& PGS_HORZ
)
529 nmpgScroll
.iScroll
= rcWnd
.right
- rcWnd
.left
;
530 nmpgScroll
.iXpos
= infoPtr
->nPos
;
534 nmpgScroll
.iScroll
= rcWnd
.bottom
- rcWnd
.top
;
535 nmpgScroll
.iYpos
= infoPtr
->nPos
;
537 nmpgScroll
.iScroll
-= 2*infoPtr
->nButtonSize
;
539 SendMessageW (infoPtr
->hwndNotify
, WM_NOTIFY
, nmpgScroll
.hdr
.idFrom
, (LPARAM
)&nmpgScroll
);
541 TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", infoPtr
->hwndSelf
, nmpgScroll
.iScroll
);
543 if (nmpgScroll
.iScroll
> 0)
545 infoPtr
->direction
= dir
;
547 if (dir
== PGF_SCROLLLEFT
|| dir
== PGF_SCROLLUP
)
548 PAGER_SetPos(infoPtr
, infoPtr
->nPos
- nmpgScroll
.iScroll
, TRUE
, TRUE
);
550 PAGER_SetPos(infoPtr
, infoPtr
->nPos
+ nmpgScroll
.iScroll
, TRUE
, TRUE
);
553 infoPtr
->direction
= -1;
558 PAGER_FmtLines(const PAGER_INFO
*infoPtr
)
560 /* initiate NCCalcSize to resize client wnd and get size */
561 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
562 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
563 SWP_NOZORDER
| SWP_NOACTIVATE
);
565 SetWindowPos(infoPtr
->hwndChild
, 0,
566 0,0,infoPtr
->nWidth
,infoPtr
->nHeight
,
569 return DefWindowProcW (infoPtr
->hwndSelf
, EM_FMTLINES
, 0, 0);
573 PAGER_Create (HWND hwnd
, const CREATESTRUCTW
*lpcs
)
578 /* allocate memory for info structure */
579 infoPtr
= heap_alloc_zero (sizeof(*infoPtr
));
580 if (!infoPtr
) return -1;
581 SetWindowLongPtrW (hwnd
, 0, (DWORD_PTR
)infoPtr
);
583 /* set default settings */
584 infoPtr
->hwndSelf
= hwnd
;
585 infoPtr
->hwndChild
= NULL
;
586 infoPtr
->hwndNotify
= lpcs
->hwndParent
;
587 infoPtr
->dwStyle
= lpcs
->style
;
588 infoPtr
->clrBk
= GetSysColor(COLOR_BTNFACE
);
589 infoPtr
->nBorder
= 0;
590 infoPtr
->nButtonSize
= 12;
593 infoPtr
->nHeight
= 0;
594 infoPtr
->bForward
= FALSE
;
595 infoPtr
->bCapture
= FALSE
;
596 infoPtr
->TLbtnState
= PGF_INVISIBLE
;
597 infoPtr
->BRbtnState
= PGF_INVISIBLE
;
598 infoPtr
->direction
= -1;
600 if (infoPtr
->dwStyle
& PGS_DRAGNDROP
)
601 FIXME("[%p] Drag and Drop style is not implemented yet.\n", infoPtr
->hwndSelf
);
603 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)infoPtr
->hwndSelf
, NF_QUERY
);
604 infoPtr
->bUnicode
= (ret
== NFR_UNICODE
);
611 PAGER_Destroy (PAGER_INFO
*infoPtr
)
613 SetWindowLongPtrW (infoPtr
->hwndSelf
, 0, 0);
614 heap_free (infoPtr
->pwszBuffer
);
620 PAGER_NCCalcSize(PAGER_INFO
* infoPtr
, WPARAM wParam
, LPRECT lpRect
)
622 RECT rcChild
, rcWindow
;
625 * lpRect points to a RECT struct. On entry, the struct
626 * contains the proposed wnd rectangle for the window.
627 * On exit, the struct should contain the screen
628 * coordinates of the corresponding window's client area.
631 DefWindowProcW (infoPtr
->hwndSelf
, WM_NCCALCSIZE
, wParam
, (LPARAM
)lpRect
);
633 TRACE("orig rect=%s\n", wine_dbgstr_rect(lpRect
));
635 GetWindowRect (infoPtr
->hwndChild
, &rcChild
);
636 MapWindowPoints (0, infoPtr
->hwndSelf
, (LPPOINT
)&rcChild
, 2); /* FIXME: RECT != 2 POINTS */
637 GetWindowRect (infoPtr
->hwndSelf
, &rcWindow
);
639 infoPtr
->nWidth
= lpRect
->right
- lpRect
->left
;
640 infoPtr
->nHeight
= lpRect
->bottom
- lpRect
->top
;
641 PAGER_CalcSize( infoPtr
);
643 if (infoPtr
->dwStyle
& PGS_HORZ
)
645 if (infoPtr
->TLbtnState
&& (lpRect
->left
+ infoPtr
->nButtonSize
< lpRect
->right
))
646 lpRect
->left
+= infoPtr
->nButtonSize
;
647 if (infoPtr
->BRbtnState
&& (lpRect
->right
- infoPtr
->nButtonSize
> lpRect
->left
))
648 lpRect
->right
-= infoPtr
->nButtonSize
;
652 if (infoPtr
->TLbtnState
&& (lpRect
->top
+ infoPtr
->nButtonSize
< lpRect
->bottom
))
653 lpRect
->top
+= infoPtr
->nButtonSize
;
654 if (infoPtr
->BRbtnState
&& (lpRect
->bottom
- infoPtr
->nButtonSize
> lpRect
->top
))
655 lpRect
->bottom
-= infoPtr
->nButtonSize
;
658 TRACE("nPos=%d, nHeight=%d, window=%s\n", infoPtr
->nPos
, infoPtr
->nHeight
, wine_dbgstr_rect(&rcWindow
));
659 TRACE("[%p] client rect set to %s BtnState[%d,%d]\n", infoPtr
->hwndSelf
, wine_dbgstr_rect(lpRect
),
660 infoPtr
->TLbtnState
, infoPtr
->BRbtnState
);
666 PAGER_NCPaint (const PAGER_INFO
* infoPtr
, HRGN hRgn
)
668 RECT rcBottomRight
, rcTopLeft
;
671 if (infoPtr
->dwStyle
& WS_MINIMIZE
)
674 DefWindowProcW (infoPtr
->hwndSelf
, WM_NCPAINT
, (WPARAM
)hRgn
, 0);
676 if (!(hdc
= GetDCEx (infoPtr
->hwndSelf
, 0, DCX_USESTYLE
| DCX_WINDOW
)))
679 PAGER_GetButtonRects(infoPtr
, &rcTopLeft
, &rcBottomRight
, FALSE
);
681 PAGER_DrawButton(hdc
, infoPtr
->clrBk
, rcTopLeft
,
682 infoPtr
->dwStyle
& PGS_HORZ
, TRUE
, infoPtr
->TLbtnState
);
683 PAGER_DrawButton(hdc
, infoPtr
->clrBk
, rcBottomRight
,
684 infoPtr
->dwStyle
& PGS_HORZ
, FALSE
, infoPtr
->BRbtnState
);
686 ReleaseDC( infoPtr
->hwndSelf
, hdc
);
691 PAGER_HitTest (const PAGER_INFO
* infoPtr
, const POINT
* pt
)
693 RECT clientRect
, rcTopLeft
, rcBottomRight
;
696 GetClientRect (infoPtr
->hwndSelf
, &clientRect
);
698 if (PtInRect(&clientRect
, *pt
))
705 PAGER_GetButtonRects(infoPtr
, &rcTopLeft
, &rcBottomRight
, TRUE
);
707 if ((infoPtr
->TLbtnState
!= PGF_INVISIBLE
) && PtInRect(&rcTopLeft
, ptWindow
))
709 TRACE("PGB_TOPORLEFT\n");
710 return PGB_TOPORLEFT
;
712 else if ((infoPtr
->BRbtnState
!= PGF_INVISIBLE
) && PtInRect(&rcBottomRight
, ptWindow
))
714 TRACE("PGB_BOTTOMORRIGHT\n");
715 return PGB_BOTTOMORRIGHT
;
723 PAGER_NCHitTest (const PAGER_INFO
* infoPtr
, INT x
, INT y
)
731 ScreenToClient (infoPtr
->hwndSelf
, &pt
);
732 nHit
= PAGER_HitTest(infoPtr
, &pt
);
734 return (nHit
< 0) ? HTTRANSPARENT
: HTCLIENT
;
738 PAGER_MouseMove (PAGER_INFO
* infoPtr
, INT keys
, INT x
, INT y
)
742 BOOL topLeft
= FALSE
;
750 TRACE("[%p] to (%d,%d)\n", infoPtr
->hwndSelf
, x
, y
);
751 ClientToScreen(infoPtr
->hwndSelf
, &pt
);
752 GetWindowRect(infoPtr
->hwndSelf
, &wnrect
);
753 if (PtInRect(&wnrect
, pt
)) {
754 RECT topleft
, bottomright
, *rect
= NULL
;
756 PAGER_GetButtonRects(infoPtr
, &topleft
, &bottomright
, FALSE
);
759 MapWindowPoints(0, infoPtr
->hwndSelf
, &clpt
, 1);
760 hit
= PAGER_HitTest(infoPtr
, &clpt
);
761 if ((hit
== PGB_TOPORLEFT
) && (infoPtr
->TLbtnState
== PGF_NORMAL
))
765 infoPtr
->TLbtnState
= PGF_HOT
;
766 btnstate
= infoPtr
->TLbtnState
;
768 else if ((hit
== PGB_BOTTOMORRIGHT
) && (infoPtr
->BRbtnState
== PGF_NORMAL
))
772 infoPtr
->BRbtnState
= PGF_HOT
;
773 btnstate
= infoPtr
->BRbtnState
;
776 /* If in one of the buttons the capture and draw buttons */
779 TRACE("[%p] draw btn (%s), Capture %s, style %08x\n",
780 infoPtr
->hwndSelf
, wine_dbgstr_rect(rect
),
781 (infoPtr
->bCapture
) ? "TRUE" : "FALSE",
783 if (!infoPtr
->bCapture
)
785 TRACE("[%p] SetCapture\n", infoPtr
->hwndSelf
);
786 SetCapture(infoPtr
->hwndSelf
);
787 infoPtr
->bCapture
= TRUE
;
789 if (infoPtr
->dwStyle
& PGS_AUTOSCROLL
)
790 SetTimer(infoPtr
->hwndSelf
, TIMERID1
, 0x3e, 0);
791 hdc
= GetWindowDC(infoPtr
->hwndSelf
);
792 /* OffsetRect(wnrect, 0 | 1, 0 | 1) */
793 PAGER_DrawButton(hdc
, infoPtr
->clrBk
, *rect
,
794 infoPtr
->dwStyle
& PGS_HORZ
, topLeft
, btnstate
);
795 ReleaseDC(infoPtr
->hwndSelf
, hdc
);
800 /* If we think we are captured, then do release */
801 if (infoPtr
->bCapture
&& (WindowFromPoint(pt
) != infoPtr
->hwndSelf
))
805 infoPtr
->bCapture
= FALSE
;
807 if (GetCapture() == infoPtr
->hwndSelf
)
811 if (infoPtr
->TLbtnState
== PGF_GRAYED
)
813 infoPtr
->TLbtnState
= PGF_INVISIBLE
;
814 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
815 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
816 SWP_NOZORDER
| SWP_NOACTIVATE
);
818 else if (infoPtr
->TLbtnState
== PGF_HOT
)
820 infoPtr
->TLbtnState
= PGF_NORMAL
;
821 /* FIXME: just invalidate button rect */
822 RedrawWindow(infoPtr
->hwndSelf
, NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
);
825 if (infoPtr
->BRbtnState
== PGF_GRAYED
)
827 infoPtr
->BRbtnState
= PGF_INVISIBLE
;
828 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
829 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
830 SWP_NOZORDER
| SWP_NOACTIVATE
);
832 else if (infoPtr
->BRbtnState
== PGF_HOT
)
834 infoPtr
->BRbtnState
= PGF_NORMAL
;
835 /* FIXME: just invalidate button rect */
836 RedrawWindow(infoPtr
->hwndSelf
, NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
);
839 /* Notify parent of released mouse capture */
840 memset(&nmhdr
, 0, sizeof(NMHDR
));
841 nmhdr
.hwndFrom
= infoPtr
->hwndSelf
;
842 nmhdr
.idFrom
= GetWindowLongPtrW(infoPtr
->hwndSelf
, GWLP_ID
);
843 nmhdr
.code
= NM_RELEASEDCAPTURE
;
844 SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, nmhdr
.idFrom
, (LPARAM
)&nmhdr
);
846 if (IsWindow(infoPtr
->hwndSelf
))
847 KillTimer(infoPtr
->hwndSelf
, TIMERID1
);
853 PAGER_LButtonDown (PAGER_INFO
* infoPtr
, INT keys
, INT x
, INT y
)
855 BOOL repaintBtns
= FALSE
;
862 TRACE("[%p] at (%d,%d)\n", infoPtr
->hwndSelf
, x
, y
);
864 hit
= PAGER_HitTest(infoPtr
, &pt
);
866 /* put btn in DEPRESSED state */
867 if (hit
== PGB_TOPORLEFT
)
869 repaintBtns
= infoPtr
->TLbtnState
!= PGF_DEPRESSED
;
870 infoPtr
->TLbtnState
= PGF_DEPRESSED
;
871 SetTimer(infoPtr
->hwndSelf
, TIMERID1
, INITIAL_DELAY
, 0);
873 else if (hit
== PGB_BOTTOMORRIGHT
)
875 repaintBtns
= infoPtr
->BRbtnState
!= PGF_DEPRESSED
;
876 infoPtr
->BRbtnState
= PGF_DEPRESSED
;
877 SetTimer(infoPtr
->hwndSelf
, TIMERID1
, INITIAL_DELAY
, 0);
881 SendMessageW(infoPtr
->hwndSelf
, WM_NCPAINT
, 0, 0);
886 if (infoPtr
->dwStyle
& PGS_HORZ
)
888 TRACE("[%p] PGF_SCROLLLEFT\n", infoPtr
->hwndSelf
);
889 PAGER_Scroll(infoPtr
, PGF_SCROLLLEFT
);
893 TRACE("[%p] PGF_SCROLLUP\n", infoPtr
->hwndSelf
);
894 PAGER_Scroll(infoPtr
, PGF_SCROLLUP
);
897 case PGB_BOTTOMORRIGHT
:
898 if (infoPtr
->dwStyle
& PGS_HORZ
)
900 TRACE("[%p] PGF_SCROLLRIGHT\n", infoPtr
->hwndSelf
);
901 PAGER_Scroll(infoPtr
, PGF_SCROLLRIGHT
);
905 TRACE("[%p] PGF_SCROLLDOWN\n", infoPtr
->hwndSelf
);
906 PAGER_Scroll(infoPtr
, PGF_SCROLLDOWN
);
917 PAGER_LButtonUp (PAGER_INFO
* infoPtr
, INT keys
, INT x
, INT y
)
919 TRACE("[%p]\n", infoPtr
->hwndSelf
);
921 KillTimer (infoPtr
->hwndSelf
, TIMERID1
);
922 KillTimer (infoPtr
->hwndSelf
, TIMERID2
);
924 /* make PRESSED btns NORMAL but don't hide gray btns */
925 if (infoPtr
->TLbtnState
& (PGF_HOT
| PGF_DEPRESSED
))
926 infoPtr
->TLbtnState
= PGF_NORMAL
;
927 if (infoPtr
->BRbtnState
& (PGF_HOT
| PGF_DEPRESSED
))
928 infoPtr
->BRbtnState
= PGF_NORMAL
;
934 PAGER_Timer (PAGER_INFO
* infoPtr
, INT nTimerId
)
938 /* if initial timer, kill it and start the repeat timer */
939 if (nTimerId
== TIMERID1
) {
940 if (infoPtr
->TLbtnState
== PGF_HOT
)
941 dir
= (infoPtr
->dwStyle
& PGS_HORZ
) ?
942 PGF_SCROLLLEFT
: PGF_SCROLLUP
;
944 dir
= (infoPtr
->dwStyle
& PGS_HORZ
) ?
945 PGF_SCROLLRIGHT
: PGF_SCROLLDOWN
;
946 TRACE("[%p] TIMERID1: style=%08x, dir=%d\n",
947 infoPtr
->hwndSelf
, infoPtr
->dwStyle
, dir
);
948 KillTimer(infoPtr
->hwndSelf
, TIMERID1
);
949 SetTimer(infoPtr
->hwndSelf
, TIMERID1
, REPEAT_DELAY
, 0);
950 if (infoPtr
->dwStyle
& PGS_AUTOSCROLL
) {
951 PAGER_Scroll(infoPtr
, dir
);
952 SetWindowPos(infoPtr
->hwndSelf
, 0, 0, 0, 0, 0,
953 SWP_FRAMECHANGED
| SWP_NOSIZE
| SWP_NOMOVE
|
954 SWP_NOZORDER
| SWP_NOACTIVATE
);
960 TRACE("[%p] TIMERID2: dir=%d\n", infoPtr
->hwndSelf
, infoPtr
->direction
);
961 KillTimer(infoPtr
->hwndSelf
, TIMERID2
);
962 if (infoPtr
->direction
> 0) {
963 PAGER_Scroll(infoPtr
, infoPtr
->direction
);
964 SetTimer(infoPtr
->hwndSelf
, TIMERID2
, REPEAT_DELAY
, 0);
970 PAGER_EraseBackground (const PAGER_INFO
* infoPtr
, HDC hdc
)
978 parent
= GetParent(infoPtr
->hwndSelf
);
979 MapWindowPoints(infoPtr
->hwndSelf
, parent
, &pt
, 1);
980 OffsetWindowOrgEx (hdc
, pt
.x
, pt
.y
, &ptorig
);
981 ret
= SendMessageW (parent
, WM_ERASEBKGND
, (WPARAM
)hdc
, 0);
982 SetWindowOrgEx (hdc
, ptorig
.x
, ptorig
.y
, 0);
989 PAGER_Size (PAGER_INFO
* infoPtr
, INT type
, INT x
, INT y
)
991 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
993 TRACE("[%p] %d,%d\n", infoPtr
->hwndSelf
, x
, y
);
995 if (infoPtr
->dwStyle
& PGS_HORZ
)
996 infoPtr
->nHeight
= y
;
1000 return PAGER_RecalcSize(infoPtr
);
1005 PAGER_StyleChanged(PAGER_INFO
*infoPtr
, WPARAM wStyleType
, const STYLESTRUCT
*lpss
)
1007 DWORD oldStyle
= infoPtr
->dwStyle
;
1009 TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
1010 wStyleType
, lpss
->styleOld
, lpss
->styleNew
);
1012 if (wStyleType
!= GWL_STYLE
) return 0;
1014 infoPtr
->dwStyle
= lpss
->styleNew
;
1016 if ((oldStyle
^ lpss
->styleNew
) & (PGS_HORZ
| PGS_VERT
))
1018 PAGER_RecalcSize(infoPtr
);
1024 static LRESULT
PAGER_NotifyFormat(PAGER_INFO
*infoPtr
, INT command
)
1030 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFYFORMAT
, (WPARAM
)infoPtr
->hwndSelf
, NF_QUERY
);
1031 infoPtr
->bUnicode
= (ret
== NFR_UNICODE
);
1034 /* Pager always wants Unicode notifications from children */
1041 static UINT
PAGER_GetAnsiNtfCode(UINT code
)
1046 case CBEN_DRAGBEGINW
: return CBEN_DRAGBEGINA
;
1047 case CBEN_ENDEDITW
: return CBEN_ENDEDITA
;
1048 case CBEN_GETDISPINFOW
: return CBEN_GETDISPINFOA
;
1049 /* Date and Time Picker */
1050 case DTN_FORMATW
: return DTN_FORMATA
;
1051 case DTN_FORMATQUERYW
: return DTN_FORMATQUERYA
;
1052 case DTN_USERSTRINGW
: return DTN_USERSTRINGA
;
1053 case DTN_WMKEYDOWNW
: return DTN_WMKEYDOWNA
;
1055 case HDN_BEGINTRACKW
: return HDN_BEGINTRACKA
;
1056 case HDN_DIVIDERDBLCLICKW
: return HDN_DIVIDERDBLCLICKA
;
1057 case HDN_ENDTRACKW
: return HDN_ENDTRACKA
;
1058 case HDN_GETDISPINFOW
: return HDN_GETDISPINFOA
;
1059 case HDN_ITEMCHANGEDW
: return HDN_ITEMCHANGEDA
;
1060 case HDN_ITEMCHANGINGW
: return HDN_ITEMCHANGINGA
;
1061 case HDN_ITEMCLICKW
: return HDN_ITEMCLICKA
;
1062 case HDN_ITEMDBLCLICKW
: return HDN_ITEMDBLCLICKA
;
1063 case HDN_TRACKW
: return HDN_TRACKA
;
1065 case LVN_BEGINLABELEDITW
: return LVN_BEGINLABELEDITA
;
1066 case LVN_ENDLABELEDITW
: return LVN_ENDLABELEDITA
;
1067 case LVN_GETDISPINFOW
: return LVN_GETDISPINFOA
;
1068 case LVN_GETINFOTIPW
: return LVN_GETINFOTIPA
;
1069 case LVN_INCREMENTALSEARCHW
: return LVN_INCREMENTALSEARCHA
;
1070 case LVN_ODFINDITEMW
: return LVN_ODFINDITEMA
;
1071 case LVN_SETDISPINFOW
: return LVN_SETDISPINFOA
;
1073 case TBN_GETBUTTONINFOW
: return TBN_GETBUTTONINFOA
;
1074 case TBN_GETINFOTIPW
: return TBN_GETINFOTIPA
;
1076 case TTN_GETDISPINFOW
: return TTN_GETDISPINFOA
;
1078 case TVN_BEGINDRAGW
: return TVN_BEGINDRAGA
;
1079 case TVN_BEGINLABELEDITW
: return TVN_BEGINLABELEDITA
;
1080 case TVN_BEGINRDRAGW
: return TVN_BEGINRDRAGA
;
1081 case TVN_DELETEITEMW
: return TVN_DELETEITEMA
;
1082 case TVN_ENDLABELEDITW
: return TVN_ENDLABELEDITA
;
1083 case TVN_GETDISPINFOW
: return TVN_GETDISPINFOA
;
1084 case TVN_GETINFOTIPW
: return TVN_GETINFOTIPA
;
1085 case TVN_ITEMEXPANDEDW
: return TVN_ITEMEXPANDEDA
;
1086 case TVN_ITEMEXPANDINGW
: return TVN_ITEMEXPANDINGA
;
1087 case TVN_SELCHANGEDW
: return TVN_SELCHANGEDA
;
1088 case TVN_SELCHANGINGW
: return TVN_SELCHANGINGA
;
1089 case TVN_SETDISPINFOW
: return TVN_SETDISPINFOA
;
1094 static BOOL
PAGER_AdjustBuffer(PAGER_INFO
*infoPtr
, INT size
)
1096 if (!infoPtr
->pwszBuffer
)
1097 infoPtr
->pwszBuffer
= heap_alloc(size
);
1098 else if (infoPtr
->nBufferSize
< size
)
1099 infoPtr
->pwszBuffer
= heap_realloc(infoPtr
->pwszBuffer
, size
);
1101 if (!infoPtr
->pwszBuffer
) return FALSE
;
1102 if (infoPtr
->nBufferSize
< size
) infoPtr
->nBufferSize
= size
;
1107 /* Convert text to Unicode and return the original text address */
1108 static WCHAR
*PAGER_ConvertText(WCHAR
**text
)
1110 WCHAR
*oldText
= *text
;
1112 Str_SetPtrWtoA((CHAR
**)text
, oldText
);
1116 static void PAGER_RestoreText(WCHAR
**text
, WCHAR
*oldText
)
1118 if (!oldText
) return;
1124 static LRESULT
PAGER_SendConvertedNotify(PAGER_INFO
*infoPtr
, NMHDR
*hdr
, UINT
*mask
, UINT requiredMask
, WCHAR
**text
,
1125 INT
*textMax
, DWORD flags
)
1127 CHAR
*sendBuffer
= NULL
;
1128 CHAR
*receiveBuffer
;
1132 LRESULT ret
= NO_ERROR
;
1135 oldTextMax
= textMax
? *textMax
: 0;
1137 hdr
->code
= PAGER_GetAnsiNtfCode(hdr
->code
);
1139 if (mask
&& !(*mask
& requiredMask
))
1141 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1142 if (flags
& SET_NULL_IF_NO_MASK
) oldText
= NULL
;
1146 if (oldTextMax
< 0) goto done
;
1148 if ((*text
&& flags
& (CONVERT_SEND
| ZERO_SEND
)) || (!*text
&& flags
& SEND_EMPTY_IF_NULL
))
1150 bufferSize
= textMax
? *textMax
: lstrlenW(*text
) + 1;
1151 sendBuffer
= heap_alloc_zero(bufferSize
);
1152 if (!sendBuffer
) goto done
;
1153 if (!(flags
& ZERO_SEND
)) WideCharToMultiByte(CP_ACP
, 0, *text
, -1, sendBuffer
, bufferSize
, NULL
, FALSE
);
1154 *text
= (WCHAR
*)sendBuffer
;
1157 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1159 if (*text
&& oldText
&& (flags
& CONVERT_RECEIVE
))
1161 /* MultiByteToWideChar requires that source and destination are not the same buffer */
1162 if (*text
== oldText
)
1164 bufferSize
= lstrlenA((CHAR
*)*text
) + 1;
1165 receiveBuffer
= heap_alloc(bufferSize
);
1166 if (!receiveBuffer
) goto done
;
1167 memcpy(receiveBuffer
, *text
, bufferSize
);
1168 MultiByteToWideChar(CP_ACP
, 0, receiveBuffer
, bufferSize
, oldText
, oldTextMax
);
1169 heap_free(receiveBuffer
);
1172 MultiByteToWideChar(CP_ACP
, 0, (CHAR
*)*text
, -1, oldText
, oldTextMax
);
1176 heap_free(sendBuffer
);
1181 static LRESULT
PAGER_Notify(PAGER_INFO
*infoPtr
, NMHDR
*hdr
)
1185 if (infoPtr
->bUnicode
) return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1190 case CBEN_GETDISPINFOW
:
1192 NMCOMBOBOXEXW
*nmcbe
= (NMCOMBOBOXEXW
*)hdr
;
1193 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmcbe
->ceItem
.mask
, CBEIF_TEXT
, &nmcbe
->ceItem
.pszText
,
1194 &nmcbe
->ceItem
.cchTextMax
, ZERO_SEND
| SET_NULL_IF_NO_MASK
| CONVERT_RECEIVE
);
1196 case CBEN_DRAGBEGINW
:
1198 NMCBEDRAGBEGINW
*nmdbW
= (NMCBEDRAGBEGINW
*)hdr
;
1199 NMCBEDRAGBEGINA nmdbA
= {{0}};
1200 nmdbA
.hdr
.code
= PAGER_GetAnsiNtfCode(nmdbW
->hdr
.code
);
1201 nmdbA
.hdr
.hwndFrom
= nmdbW
->hdr
.hwndFrom
;
1202 nmdbA
.hdr
.idFrom
= nmdbW
->hdr
.idFrom
;
1203 nmdbA
.iItemid
= nmdbW
->iItemid
;
1204 WideCharToMultiByte(CP_ACP
, 0, nmdbW
->szText
, ARRAY_SIZE(nmdbW
->szText
), nmdbA
.szText
, ARRAY_SIZE(nmdbA
.szText
),
1206 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)&nmdbA
);
1210 NMCBEENDEDITW
*nmedW
= (NMCBEENDEDITW
*)hdr
;
1211 NMCBEENDEDITA nmedA
= {{0}};
1212 nmedA
.hdr
.code
= PAGER_GetAnsiNtfCode(nmedW
->hdr
.code
);
1213 nmedA
.hdr
.hwndFrom
= nmedW
->hdr
.hwndFrom
;
1214 nmedA
.hdr
.idFrom
= nmedW
->hdr
.idFrom
;
1215 nmedA
.fChanged
= nmedW
->fChanged
;
1216 nmedA
.iNewSelection
= nmedW
->iNewSelection
;
1217 nmedA
.iWhy
= nmedW
->iWhy
;
1218 WideCharToMultiByte(CP_ACP
, 0, nmedW
->szText
, ARRAY_SIZE(nmedW
->szText
), nmedA
.szText
, ARRAY_SIZE(nmedA
.szText
),
1220 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)&nmedA
);
1222 /* Date and Time Picker */
1225 NMDATETIMEFORMATW
*nmdtf
= (NMDATETIMEFORMATW
*)hdr
;
1229 hdr
->code
= PAGER_GetAnsiNtfCode(hdr
->code
);
1230 oldFormat
= PAGER_ConvertText((WCHAR
**)&nmdtf
->pszFormat
);
1231 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)nmdtf
);
1232 PAGER_RestoreText((WCHAR
**)&nmdtf
->pszFormat
, oldFormat
);
1234 if (nmdtf
->pszDisplay
)
1236 textLength
= MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)nmdtf
->pszDisplay
, -1, 0, 0);
1237 if (!PAGER_AdjustBuffer(infoPtr
, textLength
* sizeof(WCHAR
))) return ret
;
1238 MultiByteToWideChar(CP_ACP
, 0, (LPCSTR
)nmdtf
->pszDisplay
, -1, infoPtr
->pwszBuffer
, textLength
);
1239 if (nmdtf
->pszDisplay
!= nmdtf
->szDisplay
)
1240 nmdtf
->pszDisplay
= infoPtr
->pwszBuffer
;
1243 textLength
= min(textLength
, ARRAY_SIZE(nmdtf
->szDisplay
));
1244 memcpy(nmdtf
->szDisplay
, infoPtr
->pwszBuffer
, textLength
* sizeof(WCHAR
));
1250 case DTN_FORMATQUERYW
:
1252 NMDATETIMEFORMATQUERYW
*nmdtfq
= (NMDATETIMEFORMATQUERYW
*)hdr
;
1253 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, (WCHAR
**)&nmdtfq
->pszFormat
, NULL
, CONVERT_SEND
);
1255 case DTN_WMKEYDOWNW
:
1257 NMDATETIMEWMKEYDOWNW
*nmdtkd
= (NMDATETIMEWMKEYDOWNW
*)hdr
;
1258 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, (WCHAR
**)&nmdtkd
->pszFormat
, NULL
, CONVERT_SEND
);
1260 case DTN_USERSTRINGW
:
1262 NMDATETIMESTRINGW
*nmdts
= (NMDATETIMESTRINGW
*)hdr
;
1263 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, (WCHAR
**)&nmdts
->pszUserString
, NULL
, CONVERT_SEND
);
1266 case HDN_BEGINTRACKW
:
1267 case HDN_DIVIDERDBLCLICKW
:
1269 case HDN_ITEMCHANGEDW
:
1270 case HDN_ITEMCHANGINGW
:
1271 case HDN_ITEMCLICKW
:
1272 case HDN_ITEMDBLCLICKW
:
1275 NMHEADERW
*nmh
= (NMHEADERW
*)hdr
;
1276 WCHAR
*oldText
= NULL
, *oldFilterText
= NULL
;
1277 HD_TEXTFILTERW
*tf
= NULL
;
1279 hdr
->code
= PAGER_GetAnsiNtfCode(hdr
->code
);
1281 if (!nmh
->pitem
) return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1282 if (nmh
->pitem
->mask
& HDI_TEXT
) oldText
= PAGER_ConvertText(&nmh
->pitem
->pszText
);
1283 if ((nmh
->pitem
->mask
& HDI_FILTER
) && (nmh
->pitem
->type
== HDFT_ISSTRING
) && nmh
->pitem
->pvFilter
)
1285 tf
= (HD_TEXTFILTERW
*)nmh
->pitem
->pvFilter
;
1286 oldFilterText
= PAGER_ConvertText(&tf
->pszText
);
1288 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1289 PAGER_RestoreText(&nmh
->pitem
->pszText
, oldText
);
1290 if (tf
) PAGER_RestoreText(&tf
->pszText
, oldFilterText
);
1293 case HDN_GETDISPINFOW
:
1295 NMHDDISPINFOW
*nmhddi
= (NMHDDISPINFOW
*)hdr
;
1296 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmhddi
->mask
, HDI_TEXT
, &nmhddi
->pszText
, &nmhddi
->cchTextMax
,
1297 SEND_EMPTY_IF_NULL
| CONVERT_SEND
| CONVERT_RECEIVE
);
1300 case LVN_BEGINLABELEDITW
:
1301 case LVN_ENDLABELEDITW
:
1302 case LVN_SETDISPINFOW
:
1304 NMLVDISPINFOW
*nmlvdi
= (NMLVDISPINFOW
*)hdr
;
1305 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmlvdi
->item
.mask
, LVIF_TEXT
, &nmlvdi
->item
.pszText
,
1306 &nmlvdi
->item
.cchTextMax
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
);
1308 case LVN_GETDISPINFOW
:
1310 NMLVDISPINFOW
*nmlvdi
= (NMLVDISPINFOW
*)hdr
;
1311 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmlvdi
->item
.mask
, LVIF_TEXT
, &nmlvdi
->item
.pszText
,
1312 &nmlvdi
->item
.cchTextMax
, CONVERT_RECEIVE
);
1314 case LVN_GETINFOTIPW
:
1316 NMLVGETINFOTIPW
*nmlvgit
= (NMLVGETINFOTIPW
*)hdr
;
1317 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, &nmlvgit
->pszText
, &nmlvgit
->cchTextMax
,
1318 CONVERT_SEND
| CONVERT_RECEIVE
);
1320 case LVN_INCREMENTALSEARCHW
:
1321 case LVN_ODFINDITEMW
:
1323 NMLVFINDITEMW
*nmlvfi
= (NMLVFINDITEMW
*)hdr
;
1324 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmlvfi
->lvfi
.flags
, LVFI_STRING
| LVFI_SUBSTRING
,
1325 (WCHAR
**)&nmlvfi
->lvfi
.psz
, NULL
, CONVERT_SEND
);
1328 case TBN_GETBUTTONINFOW
:
1330 NMTOOLBARW
*nmtb
= (NMTOOLBARW
*)hdr
;
1331 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, &nmtb
->pszText
, &nmtb
->cchText
,
1332 SEND_EMPTY_IF_NULL
| CONVERT_SEND
| CONVERT_RECEIVE
);
1334 case TBN_GETINFOTIPW
:
1336 NMTBGETINFOTIPW
*nmtbgit
= (NMTBGETINFOTIPW
*)hdr
;
1337 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, &nmtbgit
->pszText
, &nmtbgit
->cchTextMax
, CONVERT_RECEIVE
);
1340 case TTN_GETDISPINFOW
:
1342 NMTTDISPINFOW
*nmttdiW
= (NMTTDISPINFOW
*)hdr
;
1343 NMTTDISPINFOA nmttdiA
= {{0}};
1346 nmttdiA
.hdr
.code
= PAGER_GetAnsiNtfCode(nmttdiW
->hdr
.code
);
1347 nmttdiA
.hdr
.hwndFrom
= nmttdiW
->hdr
.hwndFrom
;
1348 nmttdiA
.hdr
.idFrom
= nmttdiW
->hdr
.idFrom
;
1349 nmttdiA
.hinst
= nmttdiW
->hinst
;
1350 nmttdiA
.uFlags
= nmttdiW
->uFlags
;
1351 nmttdiA
.lParam
= nmttdiW
->lParam
;
1352 nmttdiA
.lpszText
= nmttdiA
.szText
;
1353 WideCharToMultiByte(CP_ACP
, 0, nmttdiW
->szText
, ARRAY_SIZE(nmttdiW
->szText
), nmttdiA
.szText
,
1354 ARRAY_SIZE(nmttdiA
.szText
), NULL
, FALSE
);
1356 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)&nmttdiA
);
1358 nmttdiW
->hinst
= nmttdiA
.hinst
;
1359 nmttdiW
->uFlags
= nmttdiA
.uFlags
;
1360 nmttdiW
->lParam
= nmttdiA
.lParam
;
1362 MultiByteToWideChar(CP_ACP
, 0, nmttdiA
.szText
, ARRAY_SIZE(nmttdiA
.szText
), nmttdiW
->szText
,
1363 ARRAY_SIZE(nmttdiW
->szText
));
1364 if (!nmttdiA
.lpszText
)
1365 nmttdiW
->lpszText
= nmttdiW
->szText
;
1366 else if (!IS_INTRESOURCE(nmttdiA
.lpszText
))
1368 size
= MultiByteToWideChar(CP_ACP
, 0, nmttdiA
.lpszText
, -1, 0, 0);
1369 if (size
> ARRAY_SIZE(nmttdiW
->szText
))
1371 if (!PAGER_AdjustBuffer(infoPtr
, size
* sizeof(WCHAR
))) return ret
;
1372 MultiByteToWideChar(CP_ACP
, 0, nmttdiA
.lpszText
, -1, infoPtr
->pwszBuffer
, size
);
1373 nmttdiW
->lpszText
= infoPtr
->pwszBuffer
;
1374 /* Override content in szText */
1375 memcpy(nmttdiW
->szText
, nmttdiW
->lpszText
, min(sizeof(nmttdiW
->szText
), size
* sizeof(WCHAR
)));
1379 MultiByteToWideChar(CP_ACP
, 0, nmttdiA
.lpszText
, -1, nmttdiW
->szText
, ARRAY_SIZE(nmttdiW
->szText
));
1380 nmttdiW
->lpszText
= nmttdiW
->szText
;
1385 nmttdiW
->szText
[0] = 0;
1386 nmttdiW
->lpszText
= (WCHAR
*)nmttdiA
.lpszText
;
1392 case TVN_BEGINDRAGW
:
1393 case TVN_BEGINRDRAGW
:
1394 case TVN_ITEMEXPANDEDW
:
1395 case TVN_ITEMEXPANDINGW
:
1397 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)hdr
;
1398 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmtv
->itemNew
.mask
, TVIF_TEXT
, &nmtv
->itemNew
.pszText
, NULL
,
1401 case TVN_DELETEITEMW
:
1403 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)hdr
;
1404 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmtv
->itemOld
.mask
, TVIF_TEXT
, &nmtv
->itemOld
.pszText
, NULL
,
1407 case TVN_BEGINLABELEDITW
:
1408 case TVN_ENDLABELEDITW
:
1410 NMTVDISPINFOW
*nmtvdi
= (NMTVDISPINFOW
*)hdr
;
1411 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmtvdi
->item
.mask
, TVIF_TEXT
, &nmtvdi
->item
.pszText
,
1412 &nmtvdi
->item
.cchTextMax
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
);
1414 case TVN_SELCHANGINGW
:
1415 case TVN_SELCHANGEDW
:
1417 NMTREEVIEWW
*nmtv
= (NMTREEVIEWW
*)hdr
;
1418 WCHAR
*oldItemOldText
= NULL
;
1419 WCHAR
*oldItemNewText
= NULL
;
1421 hdr
->code
= PAGER_GetAnsiNtfCode(hdr
->code
);
1423 if (!((nmtv
->itemNew
.mask
| nmtv
->itemOld
.mask
) & TVIF_TEXT
))
1424 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1426 if (nmtv
->itemOld
.mask
& TVIF_TEXT
) oldItemOldText
= PAGER_ConvertText(&nmtv
->itemOld
.pszText
);
1427 if (nmtv
->itemNew
.mask
& TVIF_TEXT
) oldItemNewText
= PAGER_ConvertText(&nmtv
->itemNew
.pszText
);
1429 ret
= SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1430 PAGER_RestoreText(&nmtv
->itemOld
.pszText
, oldItemOldText
);
1431 PAGER_RestoreText(&nmtv
->itemNew
.pszText
, oldItemNewText
);
1434 case TVN_GETDISPINFOW
:
1436 NMTVDISPINFOW
*nmtvdi
= (NMTVDISPINFOW
*)hdr
;
1437 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmtvdi
->item
.mask
, TVIF_TEXT
, &nmtvdi
->item
.pszText
,
1438 &nmtvdi
->item
.cchTextMax
, ZERO_SEND
| CONVERT_RECEIVE
);
1440 case TVN_SETDISPINFOW
:
1442 NMTVDISPINFOW
*nmtvdi
= (NMTVDISPINFOW
*)hdr
;
1443 return PAGER_SendConvertedNotify(infoPtr
, hdr
, &nmtvdi
->item
.mask
, TVIF_TEXT
, &nmtvdi
->item
.pszText
,
1444 &nmtvdi
->item
.cchTextMax
, SET_NULL_IF_NO_MASK
| CONVERT_SEND
| CONVERT_RECEIVE
);
1446 case TVN_GETINFOTIPW
:
1448 NMTVGETINFOTIPW
*nmtvgit
= (NMTVGETINFOTIPW
*)hdr
;
1449 return PAGER_SendConvertedNotify(infoPtr
, hdr
, NULL
, 0, &nmtvgit
->pszText
, &nmtvgit
->cchTextMax
, CONVERT_RECEIVE
);
1452 /* Other notifications, no need to convert */
1453 return SendMessageW(infoPtr
->hwndNotify
, WM_NOTIFY
, hdr
->idFrom
, (LPARAM
)hdr
);
1456 static LRESULT WINAPI
1457 PAGER_WindowProc (HWND hwnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1459 PAGER_INFO
*infoPtr
= (PAGER_INFO
*)GetWindowLongPtrW(hwnd
, 0);
1461 TRACE("(%p, %#x, %#lx, %#lx)\n", hwnd
, uMsg
, wParam
, lParam
);
1463 if (!infoPtr
&& (uMsg
!= WM_CREATE
))
1464 return DefWindowProcW (hwnd
, uMsg
, wParam
, lParam
);
1469 return PAGER_FmtLines(infoPtr
);
1471 case PGM_FORWARDMOUSE
:
1472 return PAGER_ForwardMouse (infoPtr
, (BOOL
)wParam
);
1474 case PGM_GETBKCOLOR
:
1475 return PAGER_GetBkColor(infoPtr
);
1478 return PAGER_GetBorder(infoPtr
);
1480 case PGM_GETBUTTONSIZE
:
1481 return PAGER_GetButtonSize(infoPtr
);
1484 return PAGER_GetPos(infoPtr
);
1486 case PGM_GETBUTTONSTATE
:
1487 return PAGER_GetButtonState (infoPtr
, (INT
)lParam
);
1489 /* case PGM_GETDROPTARGET: */
1491 case PGM_RECALCSIZE
:
1492 return PAGER_RecalcSize(infoPtr
);
1494 case PGM_SETBKCOLOR
:
1495 return PAGER_SetBkColor (infoPtr
, (COLORREF
)lParam
);
1498 return PAGER_SetBorder (infoPtr
, (INT
)lParam
);
1500 case PGM_SETBUTTONSIZE
:
1501 return PAGER_SetButtonSize (infoPtr
, (INT
)lParam
);
1504 return PAGER_SetChild (infoPtr
, (HWND
)lParam
);
1507 return PAGER_SetPos(infoPtr
, (INT
)lParam
, FALSE
, TRUE
);
1510 return PAGER_Create (hwnd
, (LPCREATESTRUCTW
)lParam
);
1513 return PAGER_Destroy (infoPtr
);
1516 return PAGER_Size (infoPtr
, (INT
)wParam
, (short)LOWORD(lParam
), (short)HIWORD(lParam
));
1519 return PAGER_NCPaint (infoPtr
, (HRGN
)wParam
);
1521 case WM_STYLECHANGED
:
1522 return PAGER_StyleChanged(infoPtr
, wParam
, (LPSTYLESTRUCT
)lParam
);
1525 return PAGER_NCCalcSize (infoPtr
, wParam
, (LPRECT
)lParam
);
1528 return PAGER_NCHitTest (infoPtr
, (short)LOWORD(lParam
), (short)HIWORD(lParam
));
1531 if (infoPtr
->bForward
&& infoPtr
->hwndChild
)
1532 PostMessageW(infoPtr
->hwndChild
, WM_MOUSEMOVE
, wParam
, lParam
);
1533 return PAGER_MouseMove (infoPtr
, (INT
)wParam
, (short)LOWORD(lParam
), (short)HIWORD(lParam
));
1535 case WM_LBUTTONDOWN
:
1536 return PAGER_LButtonDown (infoPtr
, (INT
)wParam
, (short)LOWORD(lParam
), (short)HIWORD(lParam
));
1539 return PAGER_LButtonUp (infoPtr
, (INT
)wParam
, (short)LOWORD(lParam
), (short)HIWORD(lParam
));
1542 return PAGER_EraseBackground (infoPtr
, (HDC
)wParam
);
1545 return PAGER_Timer (infoPtr
, (INT
)wParam
);
1547 case WM_NOTIFYFORMAT
:
1548 return PAGER_NotifyFormat (infoPtr
, lParam
);
1551 return PAGER_Notify (infoPtr
, (NMHDR
*)lParam
);
1554 return SendMessageW (infoPtr
->hwndNotify
, uMsg
, wParam
, lParam
);
1557 return DefWindowProcW (hwnd
, uMsg
, wParam
, lParam
);
1563 PAGER_Register (void)
1567 ZeroMemory (&wndClass
, sizeof(WNDCLASSW
));
1568 wndClass
.style
= CS_GLOBALCLASS
;
1569 wndClass
.lpfnWndProc
= PAGER_WindowProc
;
1570 wndClass
.cbClsExtra
= 0;
1571 wndClass
.cbWndExtra
= sizeof(PAGER_INFO
*);
1572 wndClass
.hCursor
= LoadCursorW (0, (LPWSTR
)IDC_ARROW
);
1573 wndClass
.hbrBackground
= (HBRUSH
)(COLOR_BTNFACE
+1);
1574 wndClass
.lpszClassName
= WC_PAGESCROLLERW
;
1576 RegisterClassW (&wndClass
);
1581 PAGER_Unregister (void)
1583 UnregisterClassW (WC_PAGESCROLLERW
, NULL
);