source: trunk/src/comctl32/pager.c@ 9370

Last change on this file since 9370 was 9370, checked in by sandervl, 23 years ago

Wine resync

File size: 44.6 KB
Line 
1/*
2 * Pager control
3 *
4 * Copyright 1998, 1999 Eric Kohl
5 *
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.
10 *
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.
15 *
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
19 *
20 * NOTES
21 * Tested primarily with the controlspy Pager application.
22 * Susan Farley (susan@codeweavers.com)
23 *
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.
29 */
30
31#include <string.h>
32#include "winbase.h"
33#include "commctrl.h"
34#include "wine/debug.h"
35
36WINE_DEFAULT_DEBUG_CHANNEL(pager);
37
38typedef struct
39{
40 HWND hwndChild; /* handle of the contained wnd */
41 BOOL bNoResize; /* set when created with CCS_NORESIZE */
42 COLORREF clrBk; /* background color */
43 INT nBorder; /* border size for the control */
44 INT nButtonSize;/* size of the pager btns */
45 INT nPos; /* scroll position */
46 INT nWidth; /* from child wnd's response to PGN_CALCSIZE */
47 INT nHeight; /* from child wnd's response to PGN_CALCSIZE */
48 BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */
49 BOOL bCapture; /* we have captured the mouse */
50 INT TLbtnState; /* state of top or left btn */
51 INT BRbtnState; /* state of bottom or right btn */
52 INT direction; /* direction of the scroll, (e.g. PGF_SCROLLUP) */
53} PAGER_INFO;
54
55#define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
56#define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
57
58#define MIN_ARROW_WIDTH 8
59#define MIN_ARROW_HEIGHT 5
60
61#define TIMERID1 1
62#define TIMERID2 2
63#define INITIAL_DELAY 500
64#define REPEAT_DELAY 50
65
66/* the horizontal arrows are:
67 *
68 * 01234 01234
69 * 1 * *
70 * 2 ** **
71 * 3*** ***
72 * 4*** ***
73 * 5 ** **
74 * 6 * *
75 * 7
76 *
77 */
78static void
79PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
80{
81 INT x, y, w, h;
82 HPEN hPen, hOldPen;
83
84 w = r.right - r.left + 1;
85 h = r.bottom - r.top + 1;
86 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
87 return; /* refuse to draw partial arrow */
88
89 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
90 hOldPen = SelectObject ( hdc, hPen );
91 if (left)
92 {
93 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
94 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
95 MoveToEx (hdc, x, y, NULL);
96 LineTo (hdc, x--, y+5); y++;
97 MoveToEx (hdc, x, y, NULL);
98 LineTo (hdc, x--, y+3); y++;
99 MoveToEx (hdc, x, y, NULL);
100 LineTo (hdc, x, y+1);
101 }
102 else
103 {
104 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
105 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
106 MoveToEx (hdc, x, y, NULL);
107 LineTo (hdc, x++, y+5); y++;
108 MoveToEx (hdc, x, y, NULL);
109 LineTo (hdc, x++, y+3); y++;
110 MoveToEx (hdc, x, y, NULL);
111 LineTo (hdc, x, y+1);
112 }
113
114 SelectObject( hdc, hOldPen );
115 DeleteObject( hPen );
116}
117
118/* the vertical arrows are:
119 *
120 * 01234567 01234567
121 * 1****** **
122 * 2 **** ****
123 * 3 ** ******
124 * 4
125 *
126 */
127static void
128PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
129{
130 INT x, y, w, h;
131 HPEN hPen, hOldPen;
132
133 w = r.right - r.left + 1;
134 h = r.bottom - r.top + 1;
135 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
136 return; /* refuse to draw partial arrow */
137
138 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
139 hOldPen = SelectObject ( hdc, hPen );
140 if (up)
141 {
142 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
143 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
144 MoveToEx (hdc, x, y, NULL);
145 LineTo (hdc, x+5, y--); x++;
146 MoveToEx (hdc, x, y, NULL);
147 LineTo (hdc, x+3, y--); x++;
148 MoveToEx (hdc, x, y, NULL);
149 LineTo (hdc, x+1, y);
150 }
151 else
152 {
153 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
154 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
155 MoveToEx (hdc, x, y, NULL);
156 LineTo (hdc, x+5, y++); x++;
157 MoveToEx (hdc, x, y, NULL);
158 LineTo (hdc, x+3, y++); x++;
159 MoveToEx (hdc, x, y, NULL);
160 LineTo (hdc, x+1, y);
161 }
162
163 SelectObject( hdc, hOldPen );
164 DeleteObject( hPen );
165}
166
167static void
168PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
169 BOOL horz, BOOL topLeft, INT btnState)
170{
171 HBRUSH hBrush, hOldBrush;
172 RECT rc = arrowRect;
173
174 if (!btnState) /* PGF_INVISIBLE */
175 return;
176
177 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
178 return;
179
180 hBrush = CreateSolidBrush(clrBk);
181 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
182
183 FillRect(hdc, &rc, hBrush);
184
185 if (btnState == PGF_HOT)
186 {
187 DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
188 if (horz)
189 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
190 else
191 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
192 }
193 else if (btnState == PGF_NORMAL)
194 {
195 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
196 if (horz)
197 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
198 else
199 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
200 }
201 else if (btnState == PGF_DEPRESSED)
202 {
203 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
204 if (horz)
205 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
206 else
207 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
208 }
209 else if (btnState == PGF_GRAYED)
210 {
211 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
212 if (horz)
213 {
214 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
215 rc.left++, rc.top++; rc.right++, rc.bottom++;
216 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
217 }
218 else
219 {
220 PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
221 rc.left++, rc.top++; rc.right++, rc.bottom++;
222 PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
223 }
224 }
225
226 SelectObject( hdc, hOldBrush );
227 DeleteObject(hBrush);
228}
229
230static void PAGER_CaptureandTrack(PAGER_INFO *infoPtr, HWND hwnd)
231{
232 TRACKMOUSEEVENT trackinfo;
233
234 TRACE("[%p] SetCapture\n", hwnd);
235 SetCapture(hwnd);
236 infoPtr->bCapture = TRUE;
237
238 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
239 trackinfo.dwFlags = TME_QUERY;
240 trackinfo.hwndTrack = hwnd;
241 trackinfo.dwHoverTime = HOVER_DEFAULT;
242
243 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
244 _TrackMouseEvent(&trackinfo);
245
246 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
247 if(!(trackinfo.dwFlags & TME_LEAVE)) {
248 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
249
250 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
251 /* and can properly deactivate the hot button */
252 _TrackMouseEvent(&trackinfo);
253 }
254}
255
256
257/* << PAGER_GetDropTarget >> */
258
259static inline LRESULT
260PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
261{
262 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
263 TRACE("[%p]\n", hwnd);
264
265 infoPtr->bForward = (BOOL)wParam;
266
267 return 0;
268}
269
270static inline LRESULT
271PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
272{
273 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
274 LRESULT btnState = PGF_INVISIBLE;
275 INT btn = (INT)lParam;
276 TRACE("[%p]\n", hwnd);
277
278 if (btn == PGB_TOPORLEFT)
279 btnState = infoPtr->TLbtnState;
280 else if (btn == PGB_BOTTOMORRIGHT)
281 btnState = infoPtr->BRbtnState;
282
283 return btnState;
284}
285
286
287static inline LRESULT
288PAGER_GetPos(HWND hwnd)
289{
290 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
291 TRACE("[%p] returns %d\n", hwnd, infoPtr->nPos);
292 return (LRESULT)infoPtr->nPos;
293}
294
295static inline LRESULT
296PAGER_GetButtonSize(HWND hwnd)
297{
298 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
299 TRACE("[%p] returns %d\n", hwnd, infoPtr->nButtonSize);
300 return (LRESULT)infoPtr->nButtonSize;
301}
302
303static inline LRESULT
304PAGER_GetBorder(HWND hwnd)
305{
306 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
307 TRACE("[%p] returns %d\n", hwnd, infoPtr->nBorder);
308 return (LRESULT)infoPtr->nBorder;
309}
310
311static inline LRESULT
312PAGER_GetBkColor(HWND hwnd)
313{
314 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
315 TRACE("[%p] returns %06lx\n", hwnd, infoPtr->clrBk);
316 return (LRESULT)infoPtr->clrBk;
317}
318
319static void
320PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
321{
322 NMPGCALCSIZE nmpgcs;
323 ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
324 nmpgcs.hdr.hwndFrom = hwnd;
325 nmpgcs.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
326 nmpgcs.hdr.code = PGN_CALCSIZE;
327 nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
328 nmpgcs.iWidth = getWidth ? *size : 0;
329 nmpgcs.iHeight = getWidth ? 0 : *size;
330 SendMessageA (GetParent (hwnd), WM_NOTIFY,
331 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
332
333 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
334
335 TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", hwnd,
336 getWidth ? "width" : "height", *size);
337}
338
339static void
340PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
341{
342 if (infoPtr->hwndChild)
343 {
344 RECT rcClient;
345 int nPos = infoPtr->nPos;
346
347 /* compensate for a grayed btn, which will soon become invisible */
348 if (infoPtr->TLbtnState == PGF_GRAYED)
349 nPos += infoPtr->nButtonSize;
350
351 GetClientRect(hwnd, &rcClient);
352
353 if (PAGER_IsHorizontal(hwnd))
354 {
355 int wndSize = max(0, rcClient.right - rcClient.left);
356 if (infoPtr->nWidth < wndSize)
357 infoPtr->nWidth = wndSize;
358
359 TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
360 infoPtr->nWidth, infoPtr->nHeight,
361 -nPos, 0);
362 SetWindowPos(infoPtr->hwndChild, 0,
363 -nPos, 0,
364 infoPtr->nWidth, infoPtr->nHeight,
365 SWP_NOZORDER);
366 }
367 else
368 {
369 int wndSize = max(0, rcClient.bottom - rcClient.top);
370 if (infoPtr->nHeight < wndSize)
371 infoPtr->nHeight = wndSize;
372
373 TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
374 infoPtr->nWidth, infoPtr->nHeight,
375 0, -nPos);
376 SetWindowPos(infoPtr->hwndChild, 0,
377 0, -nPos,
378 infoPtr->nWidth, infoPtr->nHeight,
379 SWP_NOZORDER);
380 }
381
382 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
383 }
384}
385
386static INT
387PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
388{
389 INT scrollRange = 0;
390
391 if (infoPtr->hwndChild)
392 {
393 INT wndSize, childSize;
394 RECT wndRect;
395 GetWindowRect(hwnd, &wndRect);
396
397 if (PAGER_IsHorizontal(hwnd))
398 {
399 wndSize = wndRect.right - wndRect.left;
400 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
401 childSize = infoPtr->nWidth;
402 }
403 else
404 {
405 wndSize = wndRect.bottom - wndRect.top;
406 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
407 childSize = infoPtr->nHeight;
408 }
409
410 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
411 if (childSize > wndSize)
412 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
413 }
414
415 TRACE("[%p] returns %d\n", hwnd, scrollRange);
416 return scrollRange;
417}
418
419static void
420PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
421 BOOL* needsResize, BOOL* needsRepaint)
422{
423 if (infoPtr->nPos > 0)
424 {
425 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
426 if (infoPtr->TLbtnState != PGF_DEPRESSED)
427 infoPtr->TLbtnState = PGF_NORMAL;
428 }
429 else
430 {
431 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
432 infoPtr->TLbtnState = PGF_GRAYED;
433 }
434
435 if (scrollRange <= 0)
436 {
437 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
438 infoPtr->TLbtnState = PGF_GRAYED;
439 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
440 infoPtr->BRbtnState = PGF_GRAYED;
441 }
442 else if (infoPtr->nPos < scrollRange)
443 {
444 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
445 if (infoPtr->BRbtnState != PGF_DEPRESSED)
446 infoPtr->BRbtnState = PGF_NORMAL;
447 }
448 else
449 {
450 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
451 infoPtr->BRbtnState = PGF_GRAYED;
452 }
453}
454
455
456static void
457PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
458{
459 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
460 {
461 infoPtr->TLbtnState = PGF_NORMAL;
462 *needsRepaint = TRUE;
463 }
464
465 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
466 {
467 infoPtr->BRbtnState = PGF_NORMAL;
468 *needsRepaint = TRUE;
469 }
470}
471
472static void
473PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
474{
475 if (infoPtr->TLbtnState == PGF_GRAYED)
476 {
477 infoPtr->TLbtnState = PGF_INVISIBLE;
478 *needsResize = TRUE;
479 }
480
481 if (infoPtr->BRbtnState == PGF_GRAYED)
482 {
483 infoPtr->BRbtnState = PGF_INVISIBLE;
484 *needsResize = TRUE;
485 }
486}
487
488static void
489PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
490 INT scrollRange, BOOL hideGrayBtns)
491{
492 BOOL resizeClient = FALSE;
493 BOOL repaintBtns = FALSE;
494
495 if (scrollRange < 0)
496 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
497 else
498 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
499
500 if (hideGrayBtns)
501 PAGER_HideGrayBtns(infoPtr, &resizeClient);
502
503 if (resizeClient) /* initiate NCCalcSize to resize client wnd */ {
504 SetWindowPos(hwnd, 0,0,0,0,0,
505 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
506 SWP_NOZORDER | SWP_NOACTIVATE);
507 }
508
509 if (repaintBtns)
510 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
511}
512
513static LRESULT
514PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
515{
516 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
517 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
518 INT oldPos = infoPtr->nPos;
519
520 if ((scrollRange <= 0) || (newPos < 0))
521 infoPtr->nPos = 0;
522 else if (newPos > scrollRange)
523 infoPtr->nPos = scrollRange;
524 else
525 infoPtr->nPos = newPos;
526
527 TRACE("[%p] pos=%d, oldpos=%d\n", hwnd, infoPtr->nPos, oldPos);
528
529 if (infoPtr->nPos != oldPos)
530 {
531 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
532 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
533 PAGER_PositionChildWnd(hwnd, infoPtr);
534 }
535
536 return 0;
537}
538
539static LRESULT
540PAGER_HandleWindowPosChanging(HWND hwnd, WPARAM wParam, WINDOWPOS *winpos)
541{
542 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
543
544 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
545 {
546 /* don't let the app resize the nonscrollable dimension of a control
547 * that was created with CCS_NORESIZE style
548 * (i.e. height for a horizontal pager, or width for a vertical one) */
549
550 /* except if the current dimension is 0 and app is setting for
551 * first time, then save amount as dimension. - GA 8/01 */
552
553 if (PAGER_IsHorizontal(hwnd))
554 if (!infoPtr->nHeight && winpos->cy)
555 infoPtr->nHeight = winpos->cy;
556 else
557 winpos->cy = infoPtr->nHeight;
558 else
559 if (!infoPtr->nWidth && winpos->cx)
560 infoPtr->nWidth = winpos->cx;
561 else
562 winpos->cx = infoPtr->nWidth;
563 return 0;
564 }
565
566 DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, (LPARAM)winpos);
567
568 return 1;
569}
570
571static INT
572PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
573{
574 /* Must set the non-scrollable dimension to be less than the full height/width
575 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
576 * size, and experimentation shows that affect is almost right. */
577
578 RECT wndRect;
579 INT delta, h;
580 GetWindowRect(hwnd, &wndRect);
581
582 /* see what the app says for btn width */
583 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
584
585 if (infoPtr->bNoResize)
586 {
587 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
588 if (delta > infoPtr->nButtonSize)
589 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
590 else if (delta > 0)
591 infoPtr->nWidth += infoPtr->nButtonSize / 3;
592 }
593
594 h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
595
596 TRACE("[%p] infoPtr->nWidth set to %d\n",
597 hwnd, infoPtr->nWidth);
598
599 return h;
600}
601
602static INT
603PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
604{
605 /* Must set the non-scrollable dimension to be less than the full height/width
606 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
607 * size, and experimentation shows that affect is almost right. */
608
609 RECT wndRect;
610 INT delta, w;
611 GetWindowRect(hwnd, &wndRect);
612
613 /* see what the app says for btn height */
614 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
615
616 if (infoPtr->bNoResize)
617 {
618 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
619 if (delta > infoPtr->nButtonSize)
620 infoPtr->nHeight += infoPtr->nButtonSize;
621 else if (delta > 0)
622 infoPtr->nHeight += infoPtr->nButtonSize / 3;
623 }
624
625 w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
626
627 TRACE("[%p] infoPtr->nHeight set to %d\n",
628 hwnd, infoPtr->nHeight);
629
630 return w;
631}
632
633/******************************************************************
634 * For the PGM_RECALCSIZE message (but not the other uses in *
635 * this module), the native control does only the following: *
636 * *
637 * if (some condition) *
638 * PostMessageA(hwnd, EM_FMTLINES, 0, 0); *
639 * return DefWindowProcA(hwnd, PGM_RECALCSIZE, 0, 0); *
640 * *
641 * When we figure out what the "some condition" is we will *
642 * implement that for the message processing. *
643 ******************************************************************/
644
645static LRESULT
646PAGER_RecalcSize(HWND hwnd)
647{
648 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
649
650 TRACE("[%p]\n", hwnd);
651
652 if (infoPtr->hwndChild)
653 {
654 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
655
656 if (scrollRange <= 0)
657 {
658 infoPtr->nPos = -1;
659 PAGER_SetPos(hwnd, 0, FALSE);
660 }
661 else
662 {
663 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
664 PAGER_PositionChildWnd(hwnd, infoPtr);
665 }
666 }
667
668 return 1;
669}
670
671
672static LRESULT
673PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
674{
675 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
676 COLORREF clrTemp = infoPtr->clrBk;
677
678 infoPtr->clrBk = (COLORREF)lParam;
679 TRACE("[%p] %06lx\n", hwnd, infoPtr->clrBk);
680
681 /* the native control seems to do things this way */
682 SetWindowPos(hwnd, 0,0,0,0,0,
683 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
684 SWP_NOZORDER | SWP_NOACTIVATE);
685
686 RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE);
687
688 return (LRESULT)clrTemp;
689}
690
691
692static LRESULT
693PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
694{
695 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
696 INT nTemp = infoPtr->nBorder;
697
698 infoPtr->nBorder = (INT)lParam;
699 TRACE("[%p] %d\n", hwnd, infoPtr->nBorder);
700
701 PAGER_RecalcSize(hwnd);
702
703 return (LRESULT)nTemp;
704}
705
706
707static LRESULT
708PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
709{
710 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
711 INT nTemp = infoPtr->nButtonSize;
712
713 infoPtr->nButtonSize = (INT)lParam;
714 TRACE("[%p] %d\n", hwnd, infoPtr->nButtonSize);
715
716 PAGER_RecalcSize(hwnd);
717
718 return (LRESULT)nTemp;
719}
720
721
722static LRESULT
723PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
724{
725 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
726 INT hw;
727
728 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
729
730 if (infoPtr->hwndChild)
731 {
732 TRACE("[%p] hwndChild=%p\n", hwnd, infoPtr->hwndChild);
733
734 if (PAGER_IsHorizontal(hwnd)) {
735 hw = PAGER_SetFixedHeight(hwnd, infoPtr);
736 /* adjust non-scrollable dimension to fit the child */
737 SetWindowPos(hwnd, 0, 0,0, hw, infoPtr->nHeight,
738 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
739 SWP_NOSIZE | SWP_NOACTIVATE);
740 }
741 else {
742 hw = PAGER_SetFixedWidth(hwnd, infoPtr);
743 /* adjust non-scrollable dimension to fit the child */
744 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, hw,
745 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
746 SWP_NOSIZE | SWP_NOACTIVATE);
747 }
748
749 /* position child within the page scroller */
750 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
751 0,0,0,0,
752 SWP_SHOWWINDOW | SWP_NOSIZE); /* native is 0 */
753
754 infoPtr->nPos = -1;
755 PAGER_SetPos(hwnd, 0, FALSE);
756 }
757
758 return 0;
759}
760
761static void
762PAGER_Scroll(HWND hwnd, INT dir)
763{
764 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
765 NMPGSCROLL nmpgScroll;
766 RECT rcWnd;
767
768 if (infoPtr->hwndChild)
769 {
770 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
771 nmpgScroll.hdr.hwndFrom = hwnd;
772 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
773 nmpgScroll.hdr.code = PGN_SCROLL;
774
775 GetWindowRect(hwnd, &rcWnd);
776 GetClientRect(hwnd, &nmpgScroll.rcParent);
777 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
778 nmpgScroll.iDir = dir;
779
780 if (PAGER_IsHorizontal(hwnd))
781 {
782 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
783 nmpgScroll.iXpos = infoPtr->nPos;
784 }
785 else
786 {
787 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
788 nmpgScroll.iYpos = infoPtr->nPos;
789 }
790 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
791
792 SendMessageA (GetParent(hwnd), WM_NOTIFY,
793 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
794
795 TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
796
797 if (nmpgScroll.iScroll > 0)
798 {
799 infoPtr->direction = dir;
800
801 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
802 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
803 else
804 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
805 }
806 else
807 infoPtr->direction = -1;
808 }
809}
810
811static LRESULT
812PAGER_FmtLines(HWND hwnd)
813{
814 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
815
816 /* initiate NCCalcSize to resize client wnd and get size */
817 SetWindowPos(hwnd, 0, 0,0,0,0,
818 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
819 SWP_NOZORDER | SWP_NOACTIVATE);
820
821 SetWindowPos(infoPtr->hwndChild, 0,
822 0,0,infoPtr->nWidth,infoPtr->nHeight,
823 0);
824
825 return DefWindowProcA (hwnd, EM_FMTLINES, 0, 0);
826}
827
828static LRESULT
829PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
830{
831 PAGER_INFO *infoPtr;
832 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
833
834 /* allocate memory for info structure */
835 infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
836 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
837
838 /* set default settings */
839 infoPtr->hwndChild = (HWND)NULL;
840 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
841 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
842 infoPtr->nBorder = 0;
843 infoPtr->nButtonSize = 12;
844 infoPtr->nPos = 0;
845 infoPtr->nWidth = 0;
846 infoPtr->nHeight = 0;
847 infoPtr->bForward = FALSE;
848 infoPtr->bCapture = FALSE;
849 infoPtr->TLbtnState = PGF_INVISIBLE;
850 infoPtr->BRbtnState = PGF_INVISIBLE;
851 infoPtr->direction = -1;
852
853 if (dwStyle & PGS_DRAGNDROP)
854 FIXME("[%p] Drag and Drop style is not implemented yet.\n", hwnd);
855 /*
856 * If neither horizontal nor vertical style specified, default to vertical.
857 * This is probably not necessary, since the style may be set later on as
858 * the control is initialized, but just in case it isn't, set it here.
859 */
860 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
861 {
862 dwStyle |= PGS_VERT;
863 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
864 }
865
866 return 0;
867}
868
869
870static LRESULT
871PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
872{
873 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
874 /* free pager info data */
875 COMCTL32_Free (infoPtr);
876 SetWindowLongA (hwnd, 0, 0);
877 return 0;
878}
879
880static LRESULT
881PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
882{
883 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
884 LPRECT lpRect = (LPRECT)lParam;
885 RECT rcChildw, rcmyw, wnrc, ltrc, rbrc;
886 POINT cursor;
887 BOOL resizeClient = FALSE;
888 BOOL repaintBtns = FALSE;
889 INT scrollRange;
890
891 /*
892 * lParam points to a RECT struct. On entry, the struct
893 * contains the proposed wnd rectangle for the window.
894 * On exit, the struct should contain the screen
895 * coordinates of the corresponding window's client area.
896 */
897
898 DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);
899
900 TRACE("orig rect=(%d,%d)-(%d,%d)\n",
901 lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);
902
903 if (PAGER_IsHorizontal(hwnd))
904 {
905 infoPtr->nWidth = lpRect->right - lpRect->left;
906 PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
907 GetWindowRect (infoPtr->hwndChild, &rcChildw);
908 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
909 GetCursorPos (&cursor);
910 GetWindowRect (hwnd, &rcmyw);
911
912 /* Reset buttons and hide any grey ones */
913 scrollRange = infoPtr->nWidth - (rcmyw.right - rcmyw.left);
914
915 TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%d,%d)-(%d,%d), cursor=(%ld,%ld)\n",
916 infoPtr->nPos, scrollRange, infoPtr->nHeight,
917 rcmyw.left, rcmyw.top,
918 rcmyw.right, rcmyw.bottom,
919 cursor.x, cursor.y);
920 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
921 PAGER_HideGrayBtns(infoPtr, &resizeClient);
922
923 if (PtInRect (&rcmyw, cursor)) {
924 GetWindowRect (hwnd, &wnrc);
925 ltrc = wnrc;
926 ltrc.right = ltrc.left + infoPtr->nButtonSize;
927 rbrc = wnrc;
928 rbrc.left = rbrc.right - infoPtr->nButtonSize;
929 TRACE("horz lt rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
930 ltrc.left, ltrc.top, ltrc.right, ltrc.bottom,
931 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
932 if (PtInRect (&ltrc, cursor) && infoPtr->TLbtnState)
933 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
934 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
935 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
936 }
937 if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right))
938 lpRect->left += infoPtr->nButtonSize;
939 if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left))
940 lpRect->right -= infoPtr->nButtonSize;
941 }
942 else
943 {
944 /* native does: (from trace of IE4 opening "Favorites" frame)
945 * DefWindowProc
946 * WM_NOITFY PGN_CALCSIZE w/ dwFlag=2
947 * GetWindowRect (child, &rc)
948 * MapWindowPoints (0, syspager, &rc, 2)
949 * GetCursorPos( &cur )
950 * GetWindowRect (syspager, &rc2)
951 * PtInRect (&rc2, cur.x, cur.y) rtns 0
952 * returns with rect empty
953 */
954 infoPtr->nHeight = lpRect->bottom - lpRect->top;
955 PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
956 GetWindowRect (infoPtr->hwndChild, &rcChildw);
957 MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
958 GetCursorPos (&cursor);
959 GetWindowRect (hwnd, &rcmyw);
960
961 /* Reset buttons and hide any grey ones */
962 scrollRange = infoPtr->nHeight - (rcmyw.bottom - rcmyw.top);
963
964 TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%d,%d)-(%d,%d), cursor=(%ld,%ld)\n",
965 infoPtr->nPos, scrollRange, infoPtr->nHeight,
966 rcmyw.left, rcmyw.top,
967 rcmyw.right, rcmyw.bottom,
968 cursor.x, cursor.y);
969 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
970 PAGER_HideGrayBtns(infoPtr, &resizeClient);
971
972 if (PtInRect (&rcmyw, cursor)) {
973
974 /* native does:
975 * GetWindowRect(pager, &rc)
976 * PtInRect(btn-left????, cur.x, cur.y)
977 * if true -> ???
978 * PtInRect(btn-right????, cur.x, cur.y)
979 * if true
980 * RedrawWindow(pager, 0, 0, 5)
981 * return TRUE
982 */
983
984 GetWindowRect (hwnd, &wnrc);
985 ltrc = wnrc;
986 ltrc.right = ltrc.left + infoPtr->nButtonSize;
987 rbrc = wnrc;
988 rbrc.left = rbrc.right - infoPtr->nButtonSize;
989 TRACE("vert lt rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
990 ltrc.left, ltrc.top, ltrc.right, ltrc.bottom,
991 rbrc.left, rbrc.top, rbrc.right, rbrc.bottom);
992 if (PtInRect (&ltrc, cursor) && infoPtr->TLbtnState)
993 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
994 if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
995 RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
996 }
997 if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom))
998 lpRect->top += infoPtr->nButtonSize;
999 if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top))
1000 lpRect->bottom -= infoPtr->nButtonSize;
1001 /* ???? */
1002 if ((lpRect->bottom < 0) || (lpRect->bottom > infoPtr->nHeight))
1003 lpRect->bottom = infoPtr->nHeight;
1004 }
1005
1006 TRACE("[%p] client rect set to %dx%d at (%d,%d) BtnState[%d,%d]\n",
1007 hwnd, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top,
1008 lpRect->left, lpRect->top,
1009 infoPtr->TLbtnState, infoPtr->BRbtnState);
1010
1011 return 0;
1012}
1013
1014static LRESULT
1015PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
1016{
1017 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
1018 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1019 RECT rcWindow, rcBottomRight, rcTopLeft;
1020 HDC hdc;
1021 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1022
1023 if (dwStyle & WS_MINIMIZE)
1024 return 0;
1025
1026 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
1027
1028 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
1029 return 0;
1030
1031 GetWindowRect (hwnd, &rcWindow);
1032 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
1033
1034 rcTopLeft = rcBottomRight = rcWindow;
1035 if (bHorizontal)
1036 {
1037 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
1038 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
1039 }
1040 else
1041 {
1042 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
1043 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
1044 }
1045
1046 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
1047 bHorizontal, TRUE, infoPtr->TLbtnState);
1048 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
1049 bHorizontal, FALSE, infoPtr->BRbtnState);
1050
1051 ReleaseDC( hwnd, hdc );
1052 return 0;
1053}
1054
1055static INT
1056PAGER_HitTest (HWND hwnd, LPPOINT pt)
1057{
1058 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1059 RECT clientRect;
1060 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1061
1062 GetClientRect (hwnd, &clientRect);
1063
1064 if (PtInRect(&clientRect, *pt))
1065 {
1066 TRACE("HTCLIENT\n");
1067 return HTCLIENT;
1068 }
1069
1070 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
1071 {
1072 if (bHorizontal)
1073 {
1074 if (pt->x < clientRect.left)
1075 {
1076 TRACE("HTLEFT\n");
1077 return HTLEFT;
1078 }
1079 }
1080 else
1081 {
1082 if (pt->y < clientRect.top)
1083 {
1084 TRACE("HTTOP\n");
1085 return HTTOP;
1086 }
1087 }
1088 }
1089
1090 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
1091 {
1092 if (bHorizontal)
1093 {
1094 if (pt->x > clientRect.right)
1095 {
1096 TRACE("HTRIGHT\n");
1097 return HTRIGHT;
1098 }
1099 }
1100 else
1101 {
1102 if (pt->y > clientRect.bottom)
1103 {
1104 TRACE("HTBOTTOM\n");
1105 return HTBOTTOM;
1106 }
1107 }
1108 }
1109
1110 TRACE("HTNOWHERE\n");
1111 return HTNOWHERE;
1112}
1113
1114static LRESULT
1115PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
1116{
1117 POINT pt;
1118
1119 pt.x = SLOWORD(lParam);
1120 pt.y = SHIWORD(lParam);
1121
1122 ScreenToClient (hwnd, &pt);
1123 return PAGER_HitTest(hwnd, &pt);
1124}
1125
1126static LRESULT
1127PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1128{
1129 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1130 BOOL notCaptured = FALSE;
1131
1132 switch(LOWORD(lParam))
1133 {
1134 case HTLEFT:
1135 case HTTOP:
1136 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
1137 infoPtr->TLbtnState = PGF_HOT;
1138 break;
1139 case HTRIGHT:
1140 case HTBOTTOM:
1141 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
1142 infoPtr->BRbtnState = PGF_HOT;
1143 break;
1144 default:
1145 return FALSE;
1146 }
1147
1148 if (notCaptured)
1149 {
1150 PAGER_CaptureandTrack(infoPtr, hwnd);
1151
1152 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1153 }
1154
1155 return TRUE;
1156}
1157
1158static LRESULT
1159PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
1160{
1161 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1162
1163 KillTimer (hwnd, TIMERID1);
1164 KillTimer (hwnd, TIMERID2);
1165
1166 TRACE("[%p] ReleaseCapture\n", hwnd);
1167 ReleaseCapture();
1168 infoPtr->bCapture = FALSE;
1169
1170 /* Notify parent of released mouse capture */
1171 {
1172 NMHDR nmhdr;
1173 ZeroMemory (&nmhdr, sizeof (NMHDR));
1174 nmhdr.hwndFrom = hwnd;
1175 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1176 nmhdr.code = NM_RELEASEDCAPTURE;
1177 SendMessageA (GetParent(hwnd), WM_NOTIFY,
1178 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1179 }
1180
1181 /* make HOT btns NORMAL and hide gray btns */
1182 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
1183
1184 return TRUE;
1185}
1186
1187static LRESULT
1188PAGER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1189{
1190 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1191 POINT clpt, pt;
1192 RECT wnrect, TLbtnrect, BRbtnrect, *btnrect = NULL;
1193 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1194 BOOL topLeft = FALSE;
1195 INT btnstate = 0;
1196 INT hit;
1197 HDC hdc;
1198
1199 pt.x = SLOWORD(lParam);
1200 pt.y = SHIWORD(lParam);
1201
1202 TRACE("[%p] to (%ld,%ld)\n", hwnd, pt.x, pt.y);
1203 ClientToScreen(hwnd, &pt);
1204 GetWindowRect(hwnd, &wnrect);
1205 if (PtInRect(&wnrect, pt)) {
1206 TLbtnrect = wnrect;
1207 BRbtnrect = wnrect;
1208 if (dwStyle & PGS_HORZ) {
1209 TLbtnrect.right = TLbtnrect.left + infoPtr->nButtonSize;
1210 BRbtnrect.left = BRbtnrect.right - infoPtr->nButtonSize;
1211 }
1212 else {
1213 TLbtnrect.bottom = TLbtnrect.top + infoPtr->nButtonSize;
1214 BRbtnrect.top = BRbtnrect.bottom - infoPtr->nButtonSize;
1215 }
1216
1217 clpt = pt;
1218 MapWindowPoints(0, hwnd, &clpt, 1);
1219 hit = PAGER_HitTest(hwnd, &clpt);
1220 if (hit == HTLEFT || hit == HTTOP) {
1221 topLeft = TRUE;
1222 btnrect = &TLbtnrect;
1223 infoPtr->TLbtnState = PGF_DEPRESSED;
1224 btnstate = infoPtr->TLbtnState;
1225 }
1226 else if (hit == HTRIGHT || hit == HTBOTTOM) {
1227 topLeft = FALSE;
1228 btnrect = &BRbtnrect;
1229 infoPtr->BRbtnState = PGF_DEPRESSED;
1230 btnstate = infoPtr->BRbtnState;
1231 }
1232
1233 /* If in one of the buttons the capture and draw buttons */
1234 if (btnrect) {
1235 TRACE("[%p] draw btn (%d,%d)-(%d,%d), Capture %s, style %08lx\n",
1236 hwnd, btnrect->left, btnrect->top,
1237 btnrect->right, btnrect->bottom,
1238 (infoPtr->bCapture) ? "TRUE" : "FALSE",
1239 dwStyle);
1240 if (!infoPtr->bCapture)
1241 PAGER_CaptureandTrack(infoPtr, hwnd);
1242 if (dwStyle & PGS_AUTOSCROLL)
1243 SetTimer(hwnd, TIMERID1, 0x3e, 0);
1244 MapWindowPoints(0, hwnd, (LPPOINT)btnrect, 2);
1245 hdc = GetWindowDC(hwnd);
1246 /* OffsetRect(wnrect, 0 | 1, 0 | 1) */
1247 PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect,
1248 PAGER_IsHorizontal(hwnd), topLeft, btnstate);
1249 ReleaseDC(hwnd, hdc);
1250 return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
1251 }
1252 }
1253
1254 /* If we think we are captured, then do release */
1255 if (infoPtr->bCapture) {
1256 infoPtr->bCapture = FALSE;
1257
1258 if (GetCapture() == hwnd) {
1259 ReleaseCapture();
1260 /* Notify parent of released mouse capture */
1261 {
1262 NMHDR nmhdr;
1263 ZeroMemory (&nmhdr, sizeof (NMHDR));
1264 nmhdr.hwndFrom = hwnd;
1265 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
1266 nmhdr.code = NM_RELEASEDCAPTURE;
1267 SendMessageA (GetParent(hwnd), WM_NOTIFY,
1268 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
1269 }
1270 }
1271 if (IsWindow(hwnd))
1272 KillTimer(hwnd, TIMERID1);
1273 }
1274 return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
1275}
1276
1277static LRESULT
1278PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1279{
1280 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1281 BOOL repaintBtns = FALSE;
1282 POINT pt;
1283 INT hit;
1284
1285 pt.x = SLOWORD(lParam);
1286 pt.y = SHIWORD(lParam);
1287
1288 TRACE("[%p] at (%d,%d)\n", hwnd, SLOWORD(lParam), SHIWORD(lParam));
1289
1290 hit = PAGER_HitTest(hwnd, &pt);
1291
1292 /* put btn in DEPRESSED state */
1293 if (hit == HTLEFT || hit == HTTOP)
1294 {
1295 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1296 infoPtr->TLbtnState = PGF_DEPRESSED;
1297 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1298 }
1299 else if (hit == HTRIGHT || hit == HTBOTTOM)
1300 {
1301 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1302 infoPtr->BRbtnState = PGF_DEPRESSED;
1303 SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1304 }
1305
1306 if (repaintBtns)
1307 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1308
1309 switch(hit)
1310 {
1311 case HTLEFT:
1312 TRACE("[%p] PGF_SCROLLLEFT\n", hwnd);
1313 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1314 break;
1315 case HTTOP:
1316 TRACE("[%p] PGF_SCROLLUP\n", hwnd);
1317 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1318 break;
1319 case HTRIGHT:
1320 TRACE("[%p] PGF_SCROLLRIGHT\n", hwnd);
1321 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1322 break;
1323 case HTBOTTOM:
1324 TRACE("[%p] PGF_SCROLLDOWN\n", hwnd);
1325 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1326 break;
1327 default:
1328 break;
1329 }
1330
1331 return TRUE;
1332}
1333
1334static LRESULT
1335PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1336{
1337 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1338 TRACE("[%p]\n", hwnd);
1339
1340 KillTimer (hwnd, TIMERID1);
1341 KillTimer (hwnd, TIMERID2);
1342
1343 /* make PRESSED btns NORMAL but don't hide gray btns */
1344 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1345
1346 return 0;
1347}
1348
1349static LRESULT
1350PAGER_NCLButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1351{
1352 POINT pt;
1353
1354 pt.x = SLOWORD(lParam);
1355 pt.y = SHIWORD(lParam);
1356
1357 TRACE("[%p] at (%d,%d)\n", hwnd, SLOWORD(lParam), SHIWORD(lParam));
1358 MapWindowPoints(0, hwnd, &pt, 1);
1359 lParam = MAKELONG(pt.x, pt.y);
1360 return PAGER_LButtonDown (hwnd, wParam, lParam);
1361}
1362
1363static LRESULT
1364PAGER_Timer (HWND hwnd, WPARAM wParam)
1365{
1366 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1367 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1368 INT dir;
1369
1370 /* if initial timer, kill it and start the repeat timer */
1371 if (wParam == TIMERID1) {
1372 if (PAGER_IsHorizontal(hwnd)) {
1373 dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1374 PGF_SCROLLLEFT : PGF_SCROLLRIGHT;
1375 }
1376 else {
1377 dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1378 PGF_SCROLLUP : PGF_SCROLLDOWN;
1379 }
1380 TRACE("[%p] TIMERID1: style=%08lx, dir=%d\n", hwnd, dwStyle, dir);
1381 KillTimer(hwnd, TIMERID1);
1382 SetTimer(hwnd, TIMERID1, REPEAT_DELAY, 0);
1383 if (dwStyle & PGS_AUTOSCROLL) {
1384 PAGER_Scroll(hwnd, dir);
1385 SetWindowPos(hwnd, 0,0,0,0,0,
1386 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
1387 SWP_NOZORDER | SWP_NOACTIVATE);
1388 }
1389 return 0;
1390
1391 }
1392
1393 TRACE("[%p] TIMERID2: dir=%d\n", hwnd, infoPtr->direction);
1394 KillTimer(hwnd, TIMERID2);
1395 if (infoPtr->direction > 0) {
1396 PAGER_Scroll(hwnd, infoPtr->direction);
1397 SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1398 }
1399 return 0;
1400}
1401
1402static LRESULT
1403PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1404{
1405 POINT pt, ptorig;
1406 HDC hdc = (HDC)wParam;
1407 HWND parent;
1408
1409 /* native does:
1410 * parent = GetParent(pager)
1411 * pt.x=0; pt.y=0; ?????
1412 * MapWindowPoints(pager, parent, &pt, 1)
1413 * OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
1414 * SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
1415 * SetWindowOrgEx(hdc, 0, 0, 0)
1416 */
1417
1418 pt.x = 0;
1419 pt.y = 0;
1420 parent = GetParent(hwnd);
1421 MapWindowPoints(hwnd, parent, &pt, 1);
1422 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
1423 SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
1424 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
1425
1426
1427#if 0
1428 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1429 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1430 RECT rect;
1431
1432 GetClientRect (hwnd, &rect);
1433 FillRect ((HDC)wParam, &rect, hBrush);
1434
1435 /* background color of the child should be the same as the pager */
1436 if (infoPtr->hwndChild)
1437 {
1438 GetClientRect (infoPtr->hwndChild, &rect);
1439 FillRect ((HDC)wParam, &rect, hBrush);
1440 }
1441
1442 DeleteObject (hBrush);
1443#endif
1444
1445 return TRUE;
1446}
1447
1448
1449static LRESULT
1450PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1451{
1452 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1453
1454 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1455 TRACE("[%p] %dx%d\n", hwnd, SLOWORD(lParam), SHIWORD(lParam));
1456
1457 if (PAGER_IsHorizontal(hwnd))
1458 infoPtr->nHeight = SHIWORD(lParam);
1459 else
1460 infoPtr->nWidth = SLOWORD(lParam);
1461
1462 return PAGER_RecalcSize(hwnd);
1463}
1464
1465
1466static LRESULT WINAPI
1467PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1468{
1469 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1470
1471 if (!infoPtr && (uMsg != WM_CREATE))
1472 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1473
1474 switch (uMsg)
1475 {
1476 case EM_FMTLINES:
1477 return PAGER_FmtLines(hwnd);
1478
1479 case PGM_FORWARDMOUSE:
1480 return PAGER_ForwardMouse (hwnd, wParam);
1481
1482 case PGM_GETBKCOLOR:
1483 return PAGER_GetBkColor(hwnd);
1484
1485 case PGM_GETBORDER:
1486 return PAGER_GetBorder(hwnd);
1487
1488 case PGM_GETBUTTONSIZE:
1489 return PAGER_GetButtonSize(hwnd);
1490
1491 case PGM_GETPOS:
1492 return PAGER_GetPos(hwnd);
1493
1494 case PGM_GETBUTTONSTATE:
1495 return PAGER_GetButtonState (hwnd, wParam, lParam);
1496
1497/* case PGM_GETDROPTARGET: */
1498
1499 case PGM_RECALCSIZE:
1500 return PAGER_RecalcSize(hwnd);
1501
1502 case PGM_SETBKCOLOR:
1503 return PAGER_SetBkColor (hwnd, wParam, lParam);
1504
1505 case PGM_SETBORDER:
1506 return PAGER_SetBorder (hwnd, wParam, lParam);
1507
1508 case PGM_SETBUTTONSIZE:
1509 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1510
1511 case PGM_SETCHILD:
1512 return PAGER_SetChild (hwnd, wParam, lParam);
1513
1514 case PGM_SETPOS:
1515 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1516
1517 case WM_CREATE:
1518 return PAGER_Create (hwnd, wParam, lParam);
1519
1520 case WM_DESTROY:
1521 return PAGER_Destroy (hwnd, wParam, lParam);
1522
1523 case WM_SIZE:
1524 return PAGER_Size (hwnd, wParam, lParam);
1525
1526 case WM_NCPAINT:
1527 return PAGER_NCPaint (hwnd, wParam, lParam);
1528
1529 case WM_WINDOWPOSCHANGING:
1530 return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1531
1532 case WM_NCCALCSIZE:
1533 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1534
1535 case WM_NCHITTEST:
1536 return PAGER_NCHitTest (hwnd, wParam, lParam);
1537
1538 case WM_SETCURSOR:
1539 {
1540 if (hwnd == (HWND)wParam)
1541 return PAGER_SetCursor(hwnd, wParam, lParam);
1542 else /* its for the child */
1543 return 0;
1544 }
1545
1546 case WM_MOUSEMOVE:
1547 if (infoPtr->bForward && infoPtr->hwndChild)
1548 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1549 return PAGER_MouseMove (hwnd, wParam, lParam);
1550
1551 case WM_MOUSELEAVE:
1552 return PAGER_MouseLeave (hwnd, wParam, lParam);
1553
1554 case WM_NCLBUTTONDOWN:
1555 return PAGER_NCLButtonDown (hwnd, wParam, lParam);
1556
1557 case WM_LBUTTONDOWN:
1558 return PAGER_LButtonDown (hwnd, wParam, lParam);
1559
1560 case WM_NCLBUTTONUP:
1561 case WM_LBUTTONUP:
1562 return PAGER_LButtonUp (hwnd, wParam, lParam);
1563
1564 case WM_ERASEBKGND:
1565 return PAGER_EraseBackground (hwnd, wParam, lParam);
1566/*
1567 case WM_PAINT:
1568 return PAGER_Paint (hwnd, wParam);
1569*/
1570 case WM_TIMER:
1571 return PAGER_Timer (hwnd, wParam);
1572
1573 case WM_NOTIFY:
1574 case WM_COMMAND:
1575 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1576
1577 default:
1578 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1579 }
1580
1581 return 0;
1582}
1583
1584
1585VOID
1586PAGER_Register (void)
1587{
1588 WNDCLASSA wndClass;
1589
1590 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1591 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1592 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1593 wndClass.cbClsExtra = 0;
1594 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1595 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1596 wndClass.hbrBackground = 0;
1597 wndClass.lpszClassName = WC_PAGESCROLLERA;
1598
1599 RegisterClassA (&wndClass);
1600}
1601
1602
1603VOID
1604PAGER_Unregister (void)
1605{
1606 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);
1607}
Note: See TracBrowser for help on using the repository browser.