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

Last change on this file since 5655 was 5416, checked in by sandervl, 24 years ago

Resync with Wine + previous merge fixes

File size: 33.0 KB
Line 
1/*
2 * Pager control
3 *
4 * Copyright 1998, 1999 Eric Kohl
5 *
6 * NOTES
7 * Tested primarily with the controlspy Pager application.
8 * Susan Farley (susan@codeweavers.com)
9 *
10 * TODO:
11 * Implement repetitive button press.
12 * Adjust arrow size relative to size of button.
13 * Allow border size changes.
14 * Implement drag and drop style.
15 */
16
17#include <string.h>
18#include "winbase.h"
19#include "commctrl.h"
20#include "debugtools.h"
21
22#ifdef __WIN32OS2__
23#include "ccbase.h"
24#define inline
25#endif
26
27DEFAULT_DEBUG_CHANNEL(pager);
28
29typedef struct
30{
31#ifdef __WIN32OS2__
32 COMCTL32_HEADER header;
33#endif
34 HWND hwndChild; /* handle of the contained wnd */
35 BOOL bNoResize; /* set when created with CCS_NORESIZE */
36 COLORREF clrBk; /* background color */
37 INT nBorder; /* border size for the control */
38 INT nButtonSize;/* size of the pager btns */
39 INT nPos; /* scroll position */
40 INT nWidth; /* from child wnd's response to PGN_CALCSIZE */
41 INT nHeight; /* from child wnd's response to PGN_CALCSIZE */
42 BOOL bForward; /* forward WM_MOUSEMOVE msgs to the contained wnd */
43 INT TLbtnState; /* state of top or left btn */
44 INT BRbtnState; /* state of bottom or right btn */
45
46} PAGER_INFO;
47
48#define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
49#define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
50
51#define MIN_ARROW_WIDTH 8
52#define MIN_ARROW_HEIGHT 5
53
54
55/* the horizontal arrows are:
56 *
57 * 01234 01234
58 * 1 * *
59 * 2 ** **
60 * 3*** ***
61 * 4*** ***
62 * 5 ** **
63 * 6 * *
64 * 7
65 *
66 */
67static void
68PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
69{
70 INT x, y, w, h;
71 HPEN hOldPen;
72
73 w = r.right - r.left + 1;
74 h = r.bottom - r.top + 1;
75 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
76 return; /* refuse to draw partial arrow */
77
78 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
79 if (left)
80 {
81 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
82 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
83 MoveToEx (hdc, x, y, NULL);
84 LineTo (hdc, x--, y+5); y++;
85 MoveToEx (hdc, x, y, NULL);
86 LineTo (hdc, x--, y+3); y++;
87 MoveToEx (hdc, x, y, NULL);
88 LineTo (hdc, x, y+1);
89 }
90 else
91 {
92 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
93 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
94 MoveToEx (hdc, x, y, NULL);
95 LineTo (hdc, x++, y+5); y++;
96 MoveToEx (hdc, x, y, NULL);
97 LineTo (hdc, x++, y+3); y++;
98 MoveToEx (hdc, x, y, NULL);
99 LineTo (hdc, x, y+1);
100 }
101
102 SelectObject( hdc, hOldPen );
103}
104
105/* the vertical arrows are:
106 *
107 * 01234567 01234567
108 * 1****** **
109 * 2 **** ****
110 * 3 ** ******
111 * 4
112 *
113 */
114static void
115PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
116{
117 INT x, y, w, h;
118 HPEN hOldPen;
119
120 w = r.right - r.left + 1;
121 h = r.bottom - r.top + 1;
122 if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
123 return; /* refuse to draw partial arrow */
124
125 hOldPen = SelectObject ( hdc, GetSysColorPen (colorRef));
126 if (up)
127 {
128 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
129 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
130 MoveToEx (hdc, x, y, NULL);
131 LineTo (hdc, x+5, y--); x++;
132 MoveToEx (hdc, x, y, NULL);
133 LineTo (hdc, x+3, y--); x++;
134 MoveToEx (hdc, x, y, NULL);
135 LineTo (hdc, x+1, y);
136 }
137 else
138 {
139 x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
140 y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
141 MoveToEx (hdc, x, y, NULL);
142 LineTo (hdc, x+5, y++); x++;
143 MoveToEx (hdc, x, y, NULL);
144 LineTo (hdc, x+3, y++); x++;
145 MoveToEx (hdc, x, y, NULL);
146 LineTo (hdc, x+1, y);
147 }
148
149 SelectObject( hdc, hOldPen );
150}
151
152static void
153PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
154 BOOL horz, BOOL topLeft, INT btnState)
155{
156 HBRUSH hBrush, hOldBrush;
157 RECT rc = arrowRect;
158
159 if (!btnState) /* PGF_INVISIBLE */
160 return;
161
162 if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
163 return;
164
165 hBrush = CreateSolidBrush(clrBk);
166 hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
167
168 FillRect(hdc, &rc, hBrush);
169
170 if (btnState == PGF_HOT)
171 {
172 rc.left++, rc.top++; rc.right++, rc.bottom++;
173 DrawEdge( hdc, &rc, EDGE_RAISED, BF_RECT);
174 if (horz)
175 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
176 else
177 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
178 rc.left--, rc.top--; rc.right--, rc.bottom--;
179 }
180 else if (btnState == PGF_NORMAL)
181 {
182 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
183 if (horz)
184 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
185 else
186 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
187 }
188 else if (btnState == PGF_DEPRESSED)
189 {
190 rc.left++, rc.top++;
191 DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
192 if (horz)
193 PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
194 else
195 PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
196 rc.left--, rc.top--;
197 }
198 else if (btnState == PGF_GRAYED)
199 {
200 DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
201 if (horz)
202 {
203 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
204 rc.left++, rc.top++; rc.right++, rc.bottom++;
205 PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
206 }
207 else
208 {
209 PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
210 rc.left++, rc.top++; rc.right++, rc.bottom++;
211 PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
212 }
213 rc.left--, rc.top--; rc.right--, rc.bottom--;
214 }
215
216 SelectObject( hdc, hOldBrush );
217 DeleteObject(hBrush);
218}
219
220/* << PAGER_GetDropTarget >> */
221
222static inline LRESULT
223PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
224{
225 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
226 TRACE("[%04x]\n", hwnd);
227
228 infoPtr->bForward = (BOOL)wParam;
229
230 return 0;
231}
232
233static inline LRESULT
234PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
235{
236 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
237 LRESULT btnState = PGF_INVISIBLE;
238 INT btn = (INT)lParam;
239 TRACE("[%04x]\n", hwnd);
240
241 if (btn == PGB_TOPORLEFT)
242 btnState = infoPtr->TLbtnState;
243 else if (btn == PGB_BOTTOMORRIGHT)
244 btnState = infoPtr->BRbtnState;
245
246 return btnState;
247}
248
249
250static inline LRESULT
251PAGER_GetPos(HWND hwnd)
252{
253 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
254 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nPos);
255 return (LRESULT)infoPtr->nPos;
256}
257
258static inline LRESULT
259PAGER_GetButtonSize(HWND hwnd)
260{
261 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
262 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nButtonSize);
263 return (LRESULT)infoPtr->nButtonSize;
264}
265
266static inline LRESULT
267PAGER_GetBorder(HWND hwnd)
268{
269 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
270 TRACE("[%04x] returns %d\n", hwnd, infoPtr->nBorder);
271 return (LRESULT)infoPtr->nBorder;
272}
273
274static inline LRESULT
275PAGER_GetBkColor(HWND hwnd)
276{
277 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
278 TRACE("[%04x] returns %06lx\n", hwnd, infoPtr->clrBk);
279 return (LRESULT)infoPtr->clrBk;
280}
281
282static void
283PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
284{
285 NMPGCALCSIZE nmpgcs;
286 ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
287 nmpgcs.hdr.hwndFrom = hwnd;
288 nmpgcs.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
289 nmpgcs.hdr.code = PGN_CALCSIZE;
290 nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
291 nmpgcs.iWidth = getWidth ? *size : 0;
292 nmpgcs.iHeight = getWidth ? 0 : *size;
293 SendMessageA (hwnd, WM_NOTIFY,
294 (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
295
296 *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
297
298 TRACE("[%04x] PGN_CALCSIZE returns %s=%d\n", hwnd,
299 getWidth ? "width" : "height", *size);
300}
301
302static void
303PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
304{
305 if (infoPtr->hwndChild)
306 {
307 RECT rcClient;
308 int nPos = infoPtr->nPos;
309
310 /* compensate for a grayed btn, which will soon become invisible */
311 if (infoPtr->TLbtnState == PGF_GRAYED)
312 nPos += infoPtr->nButtonSize;
313
314 GetClientRect(hwnd, &rcClient);
315
316 if (PAGER_IsHorizontal(hwnd))
317 {
318 int wndSize = max(0, rcClient.right - rcClient.left);
319 if (infoPtr->nWidth < wndSize)
320 infoPtr->nWidth = wndSize;
321
322 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
323 infoPtr->nWidth, infoPtr->nHeight,
324 -nPos, 0);
325 SetWindowPos(infoPtr->hwndChild, 0,
326 -nPos, 0,
327 infoPtr->nWidth, infoPtr->nHeight,
328 SWP_NOZORDER);
329 }
330 else
331 {
332 int wndSize = max(0, rcClient.bottom - rcClient.top);
333 if (infoPtr->nHeight < wndSize)
334 infoPtr->nHeight = wndSize;
335
336 TRACE("[%04x] SWP %dx%d at (%d,%d)\n", hwnd,
337 infoPtr->nWidth, infoPtr->nHeight,
338 0, -nPos);
339 SetWindowPos(infoPtr->hwndChild, 0,
340 0, -nPos,
341 infoPtr->nWidth, infoPtr->nHeight,
342 SWP_NOZORDER);
343 }
344
345 InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
346 }
347}
348
349static INT
350PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
351{
352 INT scrollRange = 0;
353
354 if (infoPtr->hwndChild)
355 {
356 INT wndSize, childSize;
357 RECT wndRect;
358 GetWindowRect(hwnd, &wndRect);
359
360 if (PAGER_IsHorizontal(hwnd))
361 {
362 wndSize = wndRect.right - wndRect.left;
363 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
364 childSize = infoPtr->nWidth;
365 }
366 else
367 {
368 wndSize = wndRect.bottom - wndRect.top;
369 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
370 childSize = infoPtr->nHeight;
371 }
372
373 TRACE("childSize = %d, wndSize = %d\n", childSize, wndSize);
374 if (childSize > wndSize)
375 scrollRange = childSize - wndSize + infoPtr->nButtonSize;
376 }
377
378 TRACE("[%04x] returns %d\n", hwnd, scrollRange);
379 return scrollRange;
380}
381
382static void
383PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
384 BOOL* needsResize, BOOL* needsRepaint)
385{
386 if (infoPtr->nPos > 0)
387 {
388 *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
389 if (infoPtr->TLbtnState != PGF_DEPRESSED)
390 infoPtr->TLbtnState = PGF_NORMAL;
391 }
392 else
393 {
394 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
395 infoPtr->TLbtnState = PGF_GRAYED;
396 }
397
398 if (scrollRange <= 0)
399 {
400 *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
401 infoPtr->TLbtnState = PGF_GRAYED;
402 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
403 infoPtr->BRbtnState = PGF_GRAYED;
404 }
405 else if (infoPtr->nPos < scrollRange)
406 {
407 *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
408 if (infoPtr->BRbtnState != PGF_DEPRESSED)
409 infoPtr->BRbtnState = PGF_NORMAL;
410 }
411 else
412 {
413 *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
414 infoPtr->BRbtnState = PGF_GRAYED;
415 }
416}
417
418
419static void
420PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
421{
422 if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
423 {
424 infoPtr->TLbtnState = PGF_NORMAL;
425 *needsRepaint = TRUE;
426 }
427
428 if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
429 {
430 infoPtr->BRbtnState = PGF_NORMAL;
431 *needsRepaint = TRUE;
432 }
433}
434
435static void
436PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
437{
438 if (infoPtr->TLbtnState == PGF_GRAYED)
439 {
440 infoPtr->TLbtnState = PGF_INVISIBLE;
441 *needsResize = TRUE;
442 }
443
444 if (infoPtr->BRbtnState == PGF_GRAYED)
445 {
446 infoPtr->BRbtnState = PGF_INVISIBLE;
447 *needsResize = TRUE;
448 }
449}
450
451static void
452PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
453 INT scrollRange, BOOL hideGrayBtns)
454{
455 BOOL resizeClient = FALSE;
456 BOOL repaintBtns = FALSE;
457
458 if (scrollRange < 0)
459 PAGER_NormalizeBtns(infoPtr, &repaintBtns);
460 else
461 PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
462
463 if (hideGrayBtns)
464 PAGER_HideGrayBtns(infoPtr, &resizeClient);
465
466 if (resizeClient) /* initiate NCCalcSize to resize client wnd */
467 SetWindowPos(hwnd, 0,0,0,0,0,
468 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
469 SWP_NOZORDER | SWP_NOACTIVATE);
470
471 if (repaintBtns)
472 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
473}
474
475static LRESULT
476PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
477{
478 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
479 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
480
481 if ((scrollRange <= 0) || (newPos < 0))
482 infoPtr->nPos = 0;
483 else if (newPos > scrollRange)
484 infoPtr->nPos = scrollRange;
485 else
486 infoPtr->nPos = newPos;
487
488 TRACE("[%04x] pos=%d\n", hwnd, infoPtr->nPos);
489
490 /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
491 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
492 PAGER_PositionChildWnd(hwnd, infoPtr);
493
494 return 0;
495}
496
497static LRESULT
498PAGER_HandleWindowPosChanging(HWND hwnd, WINDOWPOS *winpos)
499{
500 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
501
502 if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
503 {
504 /* don't let the app resize the nonscrollable dimension of a control
505 * that was created with CCS_NORESIZE style
506 * (i.e. height for a horizontal pager, or width for a vertical one) */
507
508 if (PAGER_IsHorizontal(hwnd))
509 winpos->cy = infoPtr->nHeight;
510 else
511 winpos->cx = infoPtr->nWidth;
512 }
513
514 return 0;
515}
516
517static void
518PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
519{
520 /* Must set the non-scrollable dimension to be less than the full height/width
521 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
522 * size, and experimentation shows that affect is almost right. */
523
524 RECT wndRect;
525 INT delta, h;
526 GetWindowRect(hwnd, &wndRect);
527
528 /* see what the app says for btn width */
529 PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
530
531 if (infoPtr->bNoResize)
532 {
533 delta = wndRect.right - wndRect.left - infoPtr->nWidth;
534 if (delta > infoPtr->nButtonSize)
535 infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
536 else if (delta > 0)
537 infoPtr->nWidth += infoPtr->nButtonSize / 3;
538 }
539
540 h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
541
542 /* adjust non-scrollable dimension to fit the child */
543 SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, h,
544 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
545
546
547 TRACE("[%04x] infoPtr->nWidth set to %d\n",
548 hwnd, infoPtr->nWidth);
549}
550
551static void
552PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
553{
554 /* Must set the non-scrollable dimension to be less than the full height/width
555 * so that NCCalcSize is called. The Msoft docs mention 3/4 factor for button
556 * size, and experimentation shows that affect is almost right. */
557
558 RECT wndRect;
559 INT delta, w;
560 GetWindowRect(hwnd, &wndRect);
561
562 /* see what the app says for btn height */
563 PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
564
565 if (infoPtr->bNoResize)
566 {
567 delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
568 if (delta > infoPtr->nButtonSize)
569 infoPtr->nHeight += 4 * infoPtr->nButtonSize / 3;
570 else if (delta > 0)
571 infoPtr->nHeight += infoPtr->nButtonSize / 3;
572 }
573
574 w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
575
576 /* adjust non-scrollable dimension to fit the child */
577 SetWindowPos(hwnd, 0, 0,0, w, infoPtr->nHeight,
578 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER);
579
580 TRACE("[%04x] infoPtr->nHeight set to %d\n",
581 hwnd, infoPtr->nHeight);
582}
583
584static LRESULT
585PAGER_RecalcSize(HWND hwnd)
586{
587 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
588
589 TRACE("[%04x]\n", hwnd);
590
591 if (infoPtr->hwndChild)
592 {
593 INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
594
595 if (scrollRange <= 0)
596 PAGER_SetPos(hwnd, 0, FALSE);
597 else
598 {
599 PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
600 PAGER_PositionChildWnd(hwnd, infoPtr);
601 }
602 }
603
604 return 1;
605}
606
607
608static LRESULT
609PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
610{
611 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
612 COLORREF clrTemp = infoPtr->clrBk;
613
614 infoPtr->clrBk = (COLORREF)lParam;
615 TRACE("[%04x] %06lx\n", hwnd, infoPtr->clrBk);
616
617 PAGER_RecalcSize(hwnd);
618 SendMessageA(hwnd, WM_NCPAINT, (WPARAM)0, (LPARAM)0);
619
620 return (LRESULT)clrTemp;
621}
622
623
624static LRESULT
625PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
626{
627 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
628 INT nTemp = infoPtr->nBorder;
629
630 infoPtr->nBorder = (INT)lParam;
631 TRACE("[%04x] %d\n", hwnd, infoPtr->nBorder);
632
633 PAGER_RecalcSize(hwnd);
634
635 return (LRESULT)nTemp;
636}
637
638
639static LRESULT
640PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
641{
642 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
643 INT nTemp = infoPtr->nButtonSize;
644
645 infoPtr->nButtonSize = (INT)lParam;
646 TRACE("[%04x] %d\n", hwnd, infoPtr->nButtonSize);
647
648 PAGER_RecalcSize(hwnd);
649
650 return (LRESULT)nTemp;
651}
652
653
654static LRESULT
655PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
656{
657 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
658
659 infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
660
661 if (infoPtr->hwndChild)
662 {
663 TRACE("[%04x] hwndChild=%04x\n", hwnd, infoPtr->hwndChild);
664
665 if (PAGER_IsHorizontal(hwnd))
666 PAGER_SetFixedHeight(hwnd, infoPtr);
667 else
668 PAGER_SetFixedWidth(hwnd, infoPtr);
669
670 /* position child within the page scroller */
671 SetWindowPos(infoPtr->hwndChild, HWND_TOP,
672 0,0,0,0,
673 SWP_SHOWWINDOW | SWP_NOSIZE);
674
675 PAGER_SetPos(hwnd, 0, FALSE);
676 }
677
678 return 0;
679}
680
681static void
682PAGER_Scroll(HWND hwnd, INT dir)
683{
684 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
685 NMPGSCROLL nmpgScroll;
686 RECT rcWnd;
687
688 if (infoPtr->hwndChild)
689 {
690 ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
691 nmpgScroll.hdr.hwndFrom = hwnd;
692 nmpgScroll.hdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
693 nmpgScroll.hdr.code = PGN_SCROLL;
694
695 GetWindowRect(hwnd, &rcWnd);
696 GetClientRect(hwnd, &nmpgScroll.rcParent);
697 nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
698 nmpgScroll.iDir = dir;
699
700 if (PAGER_IsHorizontal(hwnd))
701 {
702 nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
703 nmpgScroll.iXpos = infoPtr->nPos;
704 }
705 else
706 {
707 nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
708 nmpgScroll.iYpos = infoPtr->nPos;
709 }
710 nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
711
712 SendMessageA (hwnd, WM_NOTIFY,
713 (WPARAM)nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
714
715 TRACE("[%04x] PGN_SCROLL returns iScroll=%d\n", hwnd, nmpgScroll.iScroll);
716
717 if (nmpgScroll.iScroll > 0)
718 {
719 if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
720 PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
721 else
722 PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
723 }
724 }
725}
726
727static LRESULT
728PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
729{
730 PAGER_INFO *infoPtr;
731 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
732
733 /* allocate memory for info structure */
734#ifdef __WIN32OS2__
735 infoPtr =(PAGER_INFO*)initControl(hwnd,sizeof(PAGER_INFO));
736#else
737 infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
738#endif
739 SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
740
741 /* set default settings */
742 infoPtr->hwndChild = (HWND)NULL;
743 infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
744 infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
745 infoPtr->nBorder = 0;
746 infoPtr->nButtonSize = 12;
747 infoPtr->nPos = 0;
748 infoPtr->nWidth = 0;
749 infoPtr->nHeight = 0;
750 infoPtr->bForward = FALSE;
751 infoPtr->TLbtnState = PGF_INVISIBLE;
752 infoPtr->BRbtnState = PGF_INVISIBLE;
753
754 if (dwStyle & PGS_AUTOSCROLL)
755 FIXME("[%04x] Autoscroll style is not implemented yet.\n", hwnd);
756 if (dwStyle & PGS_DRAGNDROP)
757 FIXME("[%04x] Drag and Drop style is not implemented yet.\n", hwnd);
758 /*
759 * If neither horizontal nor vertical style specified, default to vertical.
760 * This is probably not necessary, since the style may be set later on as
761 * the control is initialized, but just in case it isn't, set it here.
762 */
763 if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
764 {
765 dwStyle |= PGS_VERT;
766 SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
767 }
768
769 return 0;
770}
771
772
773static LRESULT
774PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
775{
776 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
777 /* free pager info data */
778 COMCTL32_Free (infoPtr);
779 SetWindowLongA (hwnd, 0, 0);
780 return 0;
781}
782
783static LRESULT
784PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
785{
786 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
787 LPRECT lpRect = (LPRECT)lParam;
788 /*
789 * lParam points to a RECT struct. On entry, the struct
790 * contains the proposed wnd rectangle for the window.
791 * On exit, the struct should contain the screen
792 * coordinates of the corresponding window's client area.
793 */
794
795 if (PAGER_IsHorizontal(hwnd))
796 {
797 if (infoPtr->TLbtnState) /* != PGF_INVISIBLE */
798 lpRect->left += infoPtr->nButtonSize;
799 if (infoPtr->BRbtnState)
800 lpRect->right -= infoPtr->nButtonSize;
801 }
802 else
803 {
804 if (infoPtr->TLbtnState)
805 lpRect->top += infoPtr->nButtonSize;
806 if (infoPtr->BRbtnState)
807 lpRect->bottom -= infoPtr->nButtonSize;
808 }
809
810 TRACE("[%04x] client rect set to %dx%d at (%d,%d)\n", hwnd,
811 lpRect->right-lpRect->left,
812 lpRect->bottom-lpRect->top,
813 lpRect->left, lpRect->top);
814
815 return 0;
816}
817
818static LRESULT
819PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
820{
821 PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
822 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
823 RECT rcWindow, rcBottomRight, rcTopLeft;
824 HDC hdc;
825 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
826
827 if (dwStyle & WS_MINIMIZE)
828 return 0;
829
830 DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);
831
832 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
833 return 0;
834
835 GetWindowRect (hwnd, &rcWindow);
836 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);
837
838 rcTopLeft = rcBottomRight = rcWindow;
839 if (bHorizontal)
840 {
841 rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
842 rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
843 }
844 else
845 {
846 rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
847 rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
848 }
849
850 PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
851 bHorizontal, TRUE, infoPtr->TLbtnState);
852 PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
853 bHorizontal, FALSE, infoPtr->BRbtnState);
854
855 ReleaseDC( hwnd, hdc );
856 return 0;
857}
858
859static INT
860PAGER_HitTest (HWND hwnd, LPPOINT pt)
861{
862 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
863 RECT clientRect;
864 BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
865
866 GetClientRect (hwnd, &clientRect);
867
868 if (PtInRect(&clientRect, *pt))
869 {
870 /* TRACE("HTCLIENT\n"); */
871 return HTCLIENT;
872 }
873
874 if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
875 {
876 if (bHorizontal)
877 {
878 if (pt->x < clientRect.left)
879 {
880 /* TRACE("HTLEFT\n"); */
881 return HTLEFT;
882 }
883 }
884 else
885 {
886 if (pt->y < clientRect.top)
887 {
888 /* TRACE("HTTOP\n"); */
889 return HTTOP;
890 }
891 }
892 }
893
894 if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
895 {
896 if (bHorizontal)
897 {
898 if (pt->x > clientRect.right)
899 {
900 /* TRACE("HTRIGHT\n"); */
901 return HTRIGHT;
902 }
903 }
904 else
905 {
906 if (pt->y > clientRect.bottom)
907 {
908 /* TRACE("HTBOTTOM\n"); */
909 return HTBOTTOM;
910 }
911 }
912 }
913
914 /* TRACE("HTNOWHERE\n"); */
915 return HTNOWHERE;
916}
917
918static LRESULT
919PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
920{
921 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
922 ScreenToClient (hwnd, &pt);
923 return PAGER_HitTest(hwnd, &pt);
924}
925
926static LRESULT
927PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
928{
929 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
930 BOOL notCaptured = FALSE;
931
932 switch(LOWORD(lParam))
933 {
934 case HTLEFT:
935 case HTTOP:
936 if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
937 infoPtr->TLbtnState = PGF_HOT;
938 break;
939 case HTRIGHT:
940 case HTBOTTOM:
941 if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
942 infoPtr->BRbtnState = PGF_HOT;
943 break;
944 default:
945 return FALSE;
946 }
947
948 if (notCaptured)
949 {
950 TRACKMOUSEEVENT trackinfo;
951
952 TRACE("[%04x] SetCapture\n", hwnd);
953 SetCapture(hwnd);
954
955 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
956 trackinfo.dwFlags = TME_QUERY;
957 trackinfo.hwndTrack = hwnd;
958 trackinfo.dwHoverTime = HOVER_DEFAULT;
959
960 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
961 _TrackMouseEvent(&trackinfo);
962
963 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
964 if(!(trackinfo.dwFlags & TME_LEAVE)) {
965 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
966
967 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
968 /* and can properly deactivate the hot button */
969 _TrackMouseEvent(&trackinfo);
970 }
971
972 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
973 }
974
975 return TRUE;
976}
977
978static LRESULT
979PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
980{
981 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
982
983 TRACE("[%04x] ReleaseCapture\n", hwnd);
984 ReleaseCapture();
985
986 /* Notify parent of released mouse capture */
987 {
988 NMHDR nmhdr;
989 ZeroMemory (&nmhdr, sizeof (NMHDR));
990 nmhdr.hwndFrom = hwnd;
991 nmhdr.idFrom = GetWindowLongA (hwnd, GWL_ID);
992 nmhdr.code = NM_RELEASEDCAPTURE;
993 SendMessageA (GetParent(hwnd), WM_NOTIFY,
994 (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
995 }
996
997 /* make HOT btns NORMAL and hide gray btns */
998 PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);
999
1000 return TRUE;
1001}
1002
1003static LRESULT
1004PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1005{
1006 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1007 BOOL repaintBtns = FALSE;
1008 POINT pt = { SLOWORD(lParam), SHIWORD(lParam) };
1009 INT hit;
1010
1011 TRACE("[%04x]\n", hwnd);
1012
1013 hit = PAGER_HitTest(hwnd, &pt);
1014
1015 /* put btn in DEPRESSED state */
1016 if (hit == HTLEFT || hit == HTTOP)
1017 {
1018 repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
1019 infoPtr->TLbtnState = PGF_DEPRESSED;
1020 }
1021 else if (hit == HTRIGHT || hit == HTBOTTOM)
1022 {
1023 repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
1024 infoPtr->BRbtnState = PGF_DEPRESSED;
1025 }
1026
1027 if (repaintBtns)
1028 SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1029
1030 switch(hit)
1031 {
1032 case HTLEFT:
1033 TRACE("[%04x] PGF_SCROLLLEFT\n", hwnd);
1034 PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
1035 break;
1036 case HTTOP:
1037 TRACE("[%04x] PGF_SCROLLUP\n", hwnd);
1038 PAGER_Scroll(hwnd, PGF_SCROLLUP);
1039 break;
1040 case HTRIGHT:
1041 TRACE("[%04x] PGF_SCROLLRIGHT\n", hwnd);
1042 PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
1043 break;
1044 case HTBOTTOM:
1045 TRACE("[%04x] PGF_SCROLLDOWN\n", hwnd);
1046 PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
1047 break;
1048 default:
1049 break;
1050 }
1051
1052 return TRUE;
1053}
1054
1055static LRESULT
1056PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1057{
1058 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1059 TRACE("[%04x]\n", hwnd);
1060
1061 /* make PRESSED btns NORMAL but don't hide gray btns */
1062 PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
1063
1064 return 0;
1065}
1066
1067static LRESULT
1068PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1069{
1070 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1071 HBRUSH hBrush = CreateSolidBrush(infoPtr->clrBk);
1072 RECT rect;
1073
1074 GetClientRect (hwnd, &rect);
1075 FillRect ((HDC)wParam, &rect, hBrush);
1076
1077 /* background color of the child should be the same as the pager */
1078 if (infoPtr->hwndChild)
1079 {
1080 GetClientRect (infoPtr->hwndChild, &rect);
1081 FillRect ((HDC)wParam, &rect, hBrush);
1082 }
1083
1084 DeleteObject (hBrush);
1085 return TRUE;
1086}
1087
1088
1089static LRESULT
1090PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1091{
1092 /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
1093
1094 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1095 TRACE("[%04x] %dx%d\n", hwnd, LOWORD(lParam), HIWORD(lParam));
1096
1097 if (PAGER_IsHorizontal(hwnd))
1098 infoPtr->nHeight = HIWORD(lParam);
1099 else
1100 infoPtr->nWidth = LOWORD(lParam);
1101
1102 return PAGER_RecalcSize(hwnd);
1103}
1104
1105
1106static LRESULT WINAPI
1107PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1108{
1109 PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1110
1111 if (!infoPtr && (uMsg != WM_CREATE))
1112 return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1113
1114 switch (uMsg)
1115 {
1116 case PGM_FORWARDMOUSE:
1117 return PAGER_ForwardMouse (hwnd, wParam);
1118
1119 case PGM_GETBKCOLOR:
1120 return PAGER_GetBkColor(hwnd);
1121
1122 case PGM_GETBORDER:
1123 return PAGER_GetBorder(hwnd);
1124
1125 case PGM_GETBUTTONSIZE:
1126 return PAGER_GetButtonSize(hwnd);
1127
1128 case PGM_GETPOS:
1129 return PAGER_GetPos(hwnd);
1130
1131 case PGM_GETBUTTONSTATE:
1132 return PAGER_GetButtonState (hwnd, wParam, lParam);
1133
1134/* case PGM_GETDROPTARGET: */
1135
1136 case PGM_RECALCSIZE:
1137 return PAGER_RecalcSize(hwnd);
1138
1139 case PGM_SETBKCOLOR:
1140 return PAGER_SetBkColor (hwnd, wParam, lParam);
1141
1142 case PGM_SETBORDER:
1143 return PAGER_SetBorder (hwnd, wParam, lParam);
1144
1145 case PGM_SETBUTTONSIZE:
1146 return PAGER_SetButtonSize (hwnd, wParam, lParam);
1147
1148 case PGM_SETCHILD:
1149 return PAGER_SetChild (hwnd, wParam, lParam);
1150
1151 case PGM_SETPOS:
1152 return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
1153
1154 case WM_CREATE:
1155 return PAGER_Create (hwnd, wParam, lParam);
1156
1157 case WM_DESTROY:
1158 return PAGER_Destroy (hwnd, wParam, lParam);
1159
1160 case WM_SIZE:
1161 return PAGER_Size (hwnd, wParam, lParam);
1162
1163 case WM_NCPAINT:
1164 return PAGER_NCPaint (hwnd, wParam, lParam);
1165
1166 case WM_WINDOWPOSCHANGING:
1167 return PAGER_HandleWindowPosChanging (hwnd, (WINDOWPOS*)lParam);
1168
1169 case WM_NCCALCSIZE:
1170 return PAGER_NCCalcSize (hwnd, wParam, lParam);
1171
1172 case WM_NCHITTEST:
1173 return PAGER_NCHitTest (hwnd, wParam, lParam);
1174
1175 case WM_SETCURSOR:
1176 {
1177 if (hwnd == (HWND)wParam)
1178 return PAGER_SetCursor(hwnd, wParam, lParam);
1179 else /* its for the child */
1180 return 0;
1181 }
1182
1183 case WM_MOUSEMOVE:
1184 if (infoPtr->bForward && infoPtr->hwndChild)
1185 PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1186 return TRUE;
1187
1188 case WM_MOUSELEAVE:
1189 return PAGER_MouseLeave (hwnd, wParam, lParam);
1190
1191 case WM_LBUTTONDOWN:
1192 return PAGER_LButtonDown (hwnd, wParam, lParam);
1193
1194 case WM_LBUTTONUP:
1195 return PAGER_LButtonUp (hwnd, wParam, lParam);
1196
1197 case WM_ERASEBKGND:
1198 return PAGER_EraseBackground (hwnd, wParam, lParam);
1199/*
1200 case WM_PAINT:
1201 return PAGER_Paint (hwnd, wParam);
1202*/
1203 case WM_NOTIFY:
1204 case WM_COMMAND:
1205 return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);
1206
1207 default:
1208#ifdef __WIN32OS2__
1209 return defComCtl32ProcA(hwnd, uMsg, wParam, lParam);
1210#else
1211 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
1212#endif
1213 }
1214
1215 return 0;
1216}
1217
1218
1219VOID
1220PAGER_Register (void)
1221{
1222 WNDCLASSA wndClass;
1223
1224 ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1225 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1226 wndClass.lpfnWndProc = (WNDPROC)PAGER_WindowProc;
1227 wndClass.cbClsExtra = 0;
1228 wndClass.cbWndExtra = sizeof(PAGER_INFO *);
1229 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA);
1230 wndClass.hbrBackground = 0;
1231 wndClass.lpszClassName = WC_PAGESCROLLERA;
1232
1233 RegisterClassA (&wndClass);
1234}
1235
1236
1237VOID
1238PAGER_Unregister (void)
1239{
1240 UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);
1241}
1242
Note: See TracBrowser for help on using the repository browser.