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

Last change on this file since 6644 was 6644, checked in by bird, 24 years ago

Added $Id:$ keyword.

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