pager.c 44.6 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Pager control
 *
4
 * Copyright 1998, 1999 Eric Kohl
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *
6 7 8 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
20
 * NOTES
21 22
 *    Tested primarily with the controlspy Pager application.
 *       Susan Farley (susan@codeweavers.com)
Alexandre Julliard's avatar
Alexandre Julliard committed
23 24
 *
 * TODO:
25 26 27 28
 *    Implement repetitive button press.
 *    Adjust arrow size relative to size of button.
 *    Allow border size changes.
 *    Implement drag and drop style.
Alexandre Julliard's avatar
Alexandre Julliard committed
29 30
 */

31
#include <string.h>
32
#include "winbase.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include "commctrl.h"
34
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35

36
WINE_DEFAULT_DEBUG_CHANNEL(pager);
37

38 39
typedef struct
{
40
    HWND   hwndChild;  /* handle of the contained wnd */
41
    BOOL   bNoResize;  /* set when created with CCS_NORESIZE */
42 43 44 45 46
    COLORREF clrBk;    /* background color */
    INT    nBorder;    /* border size for the control */
    INT    nButtonSize;/* size of the pager btns */
    INT    nPos;       /* scroll position */
    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 51
    INT    TLbtnState; /* state of top or left btn */
    INT    BRbtnState; /* state of bottom or right btn */
52
    INT    direction;  /* direction of the scroll, (e.g. PGF_SCROLLUP) */
53
} PAGER_INFO;
Alexandre Julliard's avatar
Alexandre Julliard committed
54

55
#define PAGER_GetInfoPtr(hwnd) ((PAGER_INFO *)GetWindowLongA(hwnd, 0))
56
#define PAGER_IsHorizontal(hwnd) ((GetWindowLongA (hwnd, GWL_STYLE) & PGS_HORZ))
Alexandre Julliard's avatar
Alexandre Julliard committed
57

58 59 60
#define MIN_ARROW_WIDTH  8
#define MIN_ARROW_HEIGHT 5

61 62 63 64
#define TIMERID1         1
#define TIMERID2         2
#define INITIAL_DELAY    500
#define REPEAT_DELAY     50
65

66
/* the horizontal arrows are:
67 68 69 70 71 72 73 74
 *
 * 01234    01234
 * 1  *      *
 * 2 **      **
 * 3***      ***
 * 4***      ***
 * 5 **      **
 * 6  *      *
75
 * 7
76 77 78 79 80 81
 *
 */
static void
PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
{
    INT x, y, w, h;
82 83
    HPEN hPen, hOldPen;

84 85 86 87 88
    w = r.right - r.left + 1;
    h = r.bottom - r.top + 1;
    if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
        return;  /* refuse to draw partial arrow */

89 90
    if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
    hOldPen = SelectObject ( hdc, hPen );
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
    if (left)
    {
        x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
        y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x--, y+5); y++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x--, y+3); y++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x, y+1);
    }
    else
    {
        x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
        y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x++, y+5); y++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x++, y+3); y++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x, y+1);
    }

    SelectObject( hdc, hOldPen );
115
    DeleteObject( hPen );
116 117
}

118
/* the vertical arrows are:
119 120
 *
 * 01234567    01234567
121
 * 1******        **
122 123 124 125 126 127 128 129 130
 * 2 ****        ****
 * 3  **        ******
 * 4
 *
 */
static void
PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
{
    INT x, y, w, h;
131 132
    HPEN hPen, hOldPen;

133 134 135 136 137
    w = r.right - r.left + 1;
    h = r.bottom - r.top + 1;
    if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
        return;  /* refuse to draw partial arrow */

138 139
    if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
    hOldPen = SelectObject ( hdc, hPen );
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
    if (up)
    {
        x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
        y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+5, y--); x++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+3, y--); x++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+1, y);
    }
    else
    {
        x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
        y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+5, y++); x++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+3, y++); x++;
        MoveToEx (hdc, x, y, NULL);
        LineTo (hdc, x+1, y);
    }

    SelectObject( hdc, hOldPen );
164
    DeleteObject( hPen );
165 166 167 168 169 170 171 172 173 174 175 176 177
}

static void
PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
                 BOOL horz, BOOL topLeft, INT btnState)
{
    HBRUSH   hBrush, hOldBrush;
    RECT     rc = arrowRect;

    if (!btnState) /* PGF_INVISIBLE */
        return;

    if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
178
        return;
179 180 181 182 183 184

    hBrush = CreateSolidBrush(clrBk);
    hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);

    FillRect(hdc, &rc, hBrush);

185
    if (btnState == PGF_HOT)
186
    {
187
       DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
188 189 190 191 192
       if (horz)
           PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
       else
           PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
    }
193
    else if (btnState == PGF_NORMAL)
194 195 196 197 198 199 200
    {
       DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
       if (horz)
           PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
       else
           PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
    }
201
    else if (btnState == PGF_DEPRESSED)
202 203 204 205 206 207 208
    {
       DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
       if (horz)
           PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
       else
           PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
    }
209
    else if (btnState == PGF_GRAYED)
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
    {
       DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
       if (horz)
       {
           PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
           rc.left++, rc.top++; rc.right++, rc.bottom++;
           PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
       }
       else
       {
           PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
           rc.left++, rc.top++; rc.right++, rc.bottom++;
           PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
       }
    }

    SelectObject( hdc, hOldBrush );
    DeleteObject(hBrush);
}

230 231 232 233
static void PAGER_CaptureandTrack(PAGER_INFO *infoPtr, HWND hwnd)
{
    TRACKMOUSEEVENT trackinfo;

234
    TRACE("[%p] SetCapture\n", hwnd);
235 236 237 238 239 240 241 242 243 244 245 246 247 248
    SetCapture(hwnd);
    infoPtr->bCapture = TRUE;

    trackinfo.cbSize = sizeof(TRACKMOUSEEVENT);
    trackinfo.dwFlags = TME_QUERY;
    trackinfo.hwndTrack = hwnd;
    trackinfo.dwHoverTime = HOVER_DEFAULT;

    /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */
    _TrackMouseEvent(&trackinfo);

    /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */
    if(!(trackinfo.dwFlags & TME_LEAVE)) {
	trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */
249

250 251 252 253 254 255 256
	/* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */
	/* and can properly deactivate the hot button */
	_TrackMouseEvent(&trackinfo);
    }
}


257
/* << PAGER_GetDropTarget >> */
Alexandre Julliard's avatar
Alexandre Julliard committed
258

Patrik Stridvall's avatar
Patrik Stridvall committed
259
static inline LRESULT
260
PAGER_ForwardMouse (HWND hwnd, WPARAM wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
261
{
262
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
263
    TRACE("[%p]\n", hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
264

265
    infoPtr->bForward = (BOOL)wParam;
Alexandre Julliard's avatar
Alexandre Julliard committed
266 267 268 269

    return 0;
}

Patrik Stridvall's avatar
Patrik Stridvall committed
270
static inline LRESULT
271
PAGER_GetButtonState (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
272
{
273
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
274 275
    LRESULT btnState = PGF_INVISIBLE;
    INT btn = (INT)lParam;
276
    TRACE("[%p]\n", hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
277

278 279 280 281 282 283
    if (btn == PGB_TOPORLEFT)
        btnState = infoPtr->TLbtnState;
    else if (btn == PGB_BOTTOMORRIGHT)
        btnState = infoPtr->BRbtnState;

    return btnState;
Alexandre Julliard's avatar
Alexandre Julliard committed
284 285 286
}


Patrik Stridvall's avatar
Patrik Stridvall committed
287
static inline LRESULT
288
PAGER_GetPos(HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
289
{
290
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
291
    TRACE("[%p] returns %d\n", hwnd, infoPtr->nPos);
292 293
    return (LRESULT)infoPtr->nPos;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
294

295 296 297
static inline LRESULT
PAGER_GetButtonSize(HWND hwnd)
{
298
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
299
    TRACE("[%p] returns %d\n", hwnd, infoPtr->nButtonSize);
300
    return (LRESULT)infoPtr->nButtonSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
301 302
}

303 304 305
static inline LRESULT
PAGER_GetBorder(HWND hwnd)
{
306
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
307
    TRACE("[%p] returns %d\n", hwnd, infoPtr->nBorder);
308 309
    return (LRESULT)infoPtr->nBorder;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
310

Patrik Stridvall's avatar
Patrik Stridvall committed
311
static inline LRESULT
312
PAGER_GetBkColor(HWND hwnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
313
{
314
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
315
    TRACE("[%p] returns %06lx\n", hwnd, infoPtr->clrBk);
316 317
    return (LRESULT)infoPtr->clrBk;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
318

319 320
static void
PAGER_CalcSize (HWND hwnd, INT* size, BOOL getWidth)
321 322 323 324 325 326 327 328 329
{
    NMPGCALCSIZE nmpgcs;
    ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
    nmpgcs.hdr.hwndFrom = hwnd;
    nmpgcs.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
    nmpgcs.hdr.code = PGN_CALCSIZE;
    nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
    nmpgcs.iWidth = getWidth ? *size : 0;
    nmpgcs.iHeight = getWidth ? 0 : *size;
330
    SendMessageA (GetParent (hwnd), WM_NOTIFY,
331 332 333 334
                  (WPARAM)nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);

    *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;

335
    TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", hwnd,
336
                  getWidth ? "width" : "height", *size);
Alexandre Julliard's avatar
Alexandre Julliard committed
337 338
}

339 340 341 342 343
static void
PAGER_PositionChildWnd(HWND hwnd, PAGER_INFO* infoPtr)
{
    if (infoPtr->hwndChild)
    {
344
        RECT rcClient;
345 346 347 348 349 350
        int nPos = infoPtr->nPos;

        /* compensate for a grayed btn, which will soon become invisible */
        if (infoPtr->TLbtnState == PGF_GRAYED)
            nPos += infoPtr->nButtonSize;

351 352 353
        GetClientRect(hwnd, &rcClient);

        if (PAGER_IsHorizontal(hwnd))
354
        {
355 356 357 358
            int wndSize = max(0, rcClient.right - rcClient.left);
            if (infoPtr->nWidth < wndSize)
                infoPtr->nWidth = wndSize;

359
            TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
360 361 362 363 364
                         infoPtr->nWidth, infoPtr->nHeight,
                         -nPos, 0);
            SetWindowPos(infoPtr->hwndChild, 0,
                         -nPos, 0,
                         infoPtr->nWidth, infoPtr->nHeight,
365
                         SWP_NOZORDER);
366 367 368
        }
        else
        {
369 370 371 372
            int wndSize = max(0, rcClient.bottom - rcClient.top);
            if (infoPtr->nHeight < wndSize)
                infoPtr->nHeight = wndSize;

373
            TRACE("[%p] SWP %dx%d at (%d,%d)\n", hwnd,
374
                         infoPtr->nWidth, infoPtr->nHeight,
375 376 377 378 379 380 381
                         0, -nPos);
            SetWindowPos(infoPtr->hwndChild, 0,
                         0, -nPos,
                         infoPtr->nWidth, infoPtr->nHeight,
                         SWP_NOZORDER);
        }

382
        InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
383 384
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
385

386 387
static INT
PAGER_GetScrollRange(HWND hwnd, PAGER_INFO* infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
388
{
389
    INT scrollRange = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
390

391 392 393 394 395 396
    if (infoPtr->hwndChild)
    {
        INT wndSize, childSize;
        RECT wndRect;
        GetWindowRect(hwnd, &wndRect);

397
        if (PAGER_IsHorizontal(hwnd))
398 399 400 401 402 403 404 405 406 407 408 409
        {
            wndSize = wndRect.right - wndRect.left;
            PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);
            childSize = infoPtr->nWidth;
        }
        else
        {
            wndSize = wndRect.bottom - wndRect.top;
            PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);
            childSize = infoPtr->nHeight;
        }

410
        TRACE("childSize = %d,  wndSize = %d\n", childSize, wndSize);
411 412 413
        if (childSize > wndSize)
            scrollRange = childSize - wndSize + infoPtr->nButtonSize;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
414

415
    TRACE("[%p] returns %d\n", hwnd, scrollRange);
416
    return scrollRange;
Alexandre Julliard's avatar
Alexandre Julliard committed
417 418
}

419
static void
420 421 422 423 424 425 426 427 428 429 430 431 432 433
PAGER_GrayAndRestoreBtns(PAGER_INFO* infoPtr, INT scrollRange,
                         BOOL* needsResize, BOOL* needsRepaint)
{
    if (infoPtr->nPos > 0)
    {
        *needsResize |= !infoPtr->TLbtnState; /* PGF_INVISIBLE */
        if (infoPtr->TLbtnState != PGF_DEPRESSED)
            infoPtr->TLbtnState = PGF_NORMAL;
    }
    else
    {
        *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
        infoPtr->TLbtnState = PGF_GRAYED;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
434

435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
    if (scrollRange <= 0)
    {
        *needsRepaint |= (infoPtr->TLbtnState != PGF_GRAYED);
        infoPtr->TLbtnState = PGF_GRAYED;
        *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
        infoPtr->BRbtnState = PGF_GRAYED;
    }
    else if (infoPtr->nPos < scrollRange)
    {
        *needsResize |= !infoPtr->BRbtnState; /* PGF_INVISIBLE */
        if (infoPtr->BRbtnState != PGF_DEPRESSED)
            infoPtr->BRbtnState = PGF_NORMAL;
    }
    else
    {
        *needsRepaint |= (infoPtr->BRbtnState != PGF_GRAYED);
        infoPtr->BRbtnState = PGF_GRAYED;
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455


456
static void
457
PAGER_NormalizeBtns(PAGER_INFO* infoPtr, BOOL* needsRepaint)
Alexandre Julliard's avatar
Alexandre Julliard committed
458
{
459 460 461 462 463
    if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
    {
        infoPtr->TLbtnState = PGF_NORMAL;
        *needsRepaint = TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
464

465 466 467 468 469
    if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
    {
        infoPtr->BRbtnState = PGF_NORMAL;
        *needsRepaint = TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
470 471
}

472
static void
473 474 475 476 477 478 479
PAGER_HideGrayBtns(PAGER_INFO* infoPtr, BOOL* needsResize)
{
    if (infoPtr->TLbtnState == PGF_GRAYED)
    {
        infoPtr->TLbtnState = PGF_INVISIBLE;
        *needsResize = TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
480

481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
    if (infoPtr->BRbtnState == PGF_GRAYED)
    {
        infoPtr->BRbtnState = PGF_INVISIBLE;
        *needsResize = TRUE;
    }
}

static void
PAGER_UpdateBtns(HWND hwnd, PAGER_INFO *infoPtr,
                 INT scrollRange, BOOL hideGrayBtns)
{
    BOOL resizeClient = FALSE;
    BOOL repaintBtns = FALSE;

    if (scrollRange < 0)
        PAGER_NormalizeBtns(infoPtr, &repaintBtns);
    else
        PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);

    if (hideGrayBtns)
        PAGER_HideGrayBtns(infoPtr, &resizeClient);

503
    if (resizeClient) /* initiate NCCalcSize to resize client wnd */ {
504
        SetWindowPos(hwnd, 0,0,0,0,0,
505 506
                     SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
                     SWP_NOZORDER | SWP_NOACTIVATE);
507
    }
508 509

    if (repaintBtns)
510
        SendMessageA(hwnd, WM_NCPAINT, 0, 0);
511 512
}

513
static LRESULT
514
PAGER_SetPos(HWND hwnd, INT newPos, BOOL fromBtnPress)
Alexandre Julliard's avatar
Alexandre Julliard committed
515
{
516
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
517
    INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);
518
    INT oldPos = infoPtr->nPos;
519

520 521
    if ((scrollRange <= 0) || (newPos < 0))
        infoPtr->nPos = 0;
522
    else if (newPos > scrollRange)
523 524
        infoPtr->nPos = scrollRange;
    else
525
        infoPtr->nPos = newPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
526

527
    TRACE("[%p] pos=%d, oldpos=%d\n", hwnd, infoPtr->nPos, oldPos);
528

529 530 531 532 533 534
    if (infoPtr->nPos != oldPos)
    {
        /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
        PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, !fromBtnPress);
        PAGER_PositionChildWnd(hwnd, infoPtr);
    }
535 536 537

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
538

539
static LRESULT
540
PAGER_HandleWindowPosChanging(HWND hwnd, WPARAM wParam, WINDOWPOS *winpos)
541 542 543 544 545 546 547 548 549
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);

    if (infoPtr->bNoResize && !(winpos->flags & SWP_NOSIZE))
    {
        /* don't let the app resize the nonscrollable dimension of a control
         * that was created with CCS_NORESIZE style
         * (i.e. height for a horizontal pager, or width for a vertical one) */

550 551 552
	/* except if the current dimension is 0 and app is setting for
	 * first time, then save amount as dimension. - GA 8/01 */

553
        if (PAGER_IsHorizontal(hwnd))
554 555 556 557
	    if (!infoPtr->nHeight && winpos->cy)
		infoPtr->nHeight = winpos->cy;
	    else
		winpos->cy = infoPtr->nHeight;
558
        else
559 560 561 562 563
	    if (!infoPtr->nWidth && winpos->cx)
		infoPtr->nWidth = winpos->cx;
	    else
		winpos->cx = infoPtr->nWidth;
	return 0;
564
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
565

566 567 568
    DefWindowProcA (hwnd, WM_WINDOWPOSCHANGING, wParam, (LPARAM)winpos);

    return 1;
569
}
Alexandre Julliard's avatar
Alexandre Julliard committed
570

571
static INT
572 573 574 575 576 577 578
PAGER_SetFixedWidth(HWND hwnd, PAGER_INFO* infoPtr)
{
  /* Must set the non-scrollable dimension to be less than the full height/width
   * so that NCCalcSize is called.  The Msoft docs mention 3/4 factor for button
   * size, and experimentation shows that affect is almost right. */

    RECT wndRect;
579
    INT delta, h;
580 581 582 583 584 585 586 587 588 589 590 591 592 593
    GetWindowRect(hwnd, &wndRect);

    /* see what the app says for btn width */
    PAGER_CalcSize(hwnd, &infoPtr->nWidth, TRUE);

    if (infoPtr->bNoResize)
    {
        delta = wndRect.right - wndRect.left - infoPtr->nWidth;
        if (delta > infoPtr->nButtonSize)
            infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
        else if (delta > 0)
            infoPtr->nWidth +=  infoPtr->nButtonSize / 3;
    }

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
}

602
static INT
603 604 605 606 607 608 609
PAGER_SetFixedHeight(HWND hwnd, PAGER_INFO* infoPtr)
{
  /* Must set the non-scrollable dimension to be less than the full height/width
   * so that NCCalcSize is called.  The Msoft docs mention 3/4 factor for button
   * size, and experimentation shows that affect is almost right. */

    RECT wndRect;
610
    INT delta, w;
611 612 613 614 615 616 617 618 619
    GetWindowRect(hwnd, &wndRect);

    /* see what the app says for btn height */
    PAGER_CalcSize(hwnd, &infoPtr->nHeight, FALSE);

    if (infoPtr->bNoResize)
    {
        delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
        if (delta > infoPtr->nButtonSize)
620
            infoPtr->nHeight += infoPtr->nButtonSize;
621 622 623 624
        else if (delta > 0)
            infoPtr->nHeight +=  infoPtr->nButtonSize / 3;
    }

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 635 636 637 638 639 640 641 642 643 644
/******************************************************************
 * For the PGM_RECALCSIZE message (but not the other uses in      *
 * this module), the native control does only the following:      *
 *                                                                *
 *    if (some condition)                                         *
 *          PostMessageA(hwnd, EM_FMTLINES, 0, 0);                *
 *    return DefWindowProcA(hwnd, PGM_RECALCSIZE, 0, 0);          *
 *                                                                *
 * When we figure out what the "some condition" is we will        *
 * implement that for the message processing.                     *
 ******************************************************************/

645 646 647 648
static LRESULT
PAGER_RecalcSize(HWND hwnd)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
649

650
    TRACE("[%p]\n", hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
651

652
    if (infoPtr->hwndChild)
653
    {
654 655 656
        INT scrollRange = PAGER_GetScrollRange(hwnd, infoPtr);

        if (scrollRange <= 0)
657 658
        {
            infoPtr->nPos = -1;
659
            PAGER_SetPos(hwnd, 0, FALSE);
660
        }
661
        else
662 663 664 665
        {
            PAGER_UpdateBtns(hwnd, infoPtr, scrollRange, TRUE);
            PAGER_PositionChildWnd(hwnd, infoPtr);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
666
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
667

668
    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
669
}
Alexandre Julliard's avatar
Alexandre Julliard committed
670 671


672
static LRESULT
673
PAGER_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
674
{
675
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
676 677 678
    COLORREF clrTemp = infoPtr->clrBk;

    infoPtr->clrBk = (COLORREF)lParam;
679
    TRACE("[%p] %06lx\n", hwnd, infoPtr->clrBk);
Alexandre Julliard's avatar
Alexandre Julliard committed
680

681
    /* the native control seems to do things this way */
682
    SetWindowPos(hwnd, 0,0,0,0,0,
683 684 685 686
		 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
		 SWP_NOZORDER | SWP_NOACTIVATE);

    RedrawWindow(hwnd, 0, 0, RDW_ERASE | RDW_INVALIDATE);
Alexandre Julliard's avatar
Alexandre Julliard committed
687 688 689 690 691

    return (LRESULT)clrTemp;
}


692
static LRESULT
693
PAGER_SetBorder (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
694
{
695
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
696
    INT nTemp = infoPtr->nBorder;
Alexandre Julliard's avatar
Alexandre Julliard committed
697

698
    infoPtr->nBorder = (INT)lParam;
699
    TRACE("[%p] %d\n", hwnd, infoPtr->nBorder);
Alexandre Julliard's avatar
Alexandre Julliard committed
700

701
    PAGER_RecalcSize(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703 704 705 706

    return (LRESULT)nTemp;
}


707
static LRESULT
708
PAGER_SetButtonSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
709
{
710
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
711
    INT nTemp = infoPtr->nButtonSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
712

713
    infoPtr->nButtonSize = (INT)lParam;
714
    TRACE("[%p] %d\n", hwnd, infoPtr->nButtonSize);
Alexandre Julliard's avatar
Alexandre Julliard committed
715

716
    PAGER_RecalcSize(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
717 718 719 720 721

    return (LRESULT)nTemp;
}


722
static LRESULT
723
PAGER_SetChild (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
724
{
725
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
726
    INT hw;
Alexandre Julliard's avatar
Alexandre Julliard committed
727

728
    infoPtr->hwndChild = IsWindow ((HWND)lParam) ? (HWND)lParam : 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
729

730 731
    if (infoPtr->hwndChild)
    {
732
        TRACE("[%p] hwndChild=%p\n", hwnd, infoPtr->hwndChild);
733

734 735 736
        if (PAGER_IsHorizontal(hwnd)) {
            hw = PAGER_SetFixedHeight(hwnd, infoPtr);
	    /* adjust non-scrollable dimension to fit the child */
737
	    SetWindowPos(hwnd, 0, 0,0, hw, infoPtr->nHeight,
738 739 740 741 742 743
			 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
			 SWP_NOSIZE | SWP_NOACTIVATE);
	}
        else {
            hw = PAGER_SetFixedWidth(hwnd, infoPtr);
	    /* adjust non-scrollable dimension to fit the child */
744
	    SetWindowPos(hwnd, 0, 0,0, infoPtr->nWidth, hw,
745 746 747
			 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
			 SWP_NOSIZE | SWP_NOACTIVATE);
	}
748 749 750 751

        /* position child within the page scroller */
        SetWindowPos(infoPtr->hwndChild, HWND_TOP,
                     0,0,0,0,
752
                     SWP_SHOWWINDOW | SWP_NOSIZE);  /* native is 0 */
753

754
        infoPtr->nPos = -1;
755
        PAGER_SetPos(hwnd, 0, FALSE);
756
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
757 758 759 760

    return 0;
}

761 762
static void
PAGER_Scroll(HWND hwnd, INT dir)
Alexandre Julliard's avatar
Alexandre Julliard committed
763
{
764
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
765
    NMPGSCROLL nmpgScroll;
766
    RECT rcWnd;
Alexandre Julliard's avatar
Alexandre Julliard committed
767

768 769 770 771 772 773 774
    if (infoPtr->hwndChild)
    {
        ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
        nmpgScroll.hdr.hwndFrom = hwnd;
        nmpgScroll.hdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
        nmpgScroll.hdr.code = PGN_SCROLL;

775 776
        GetWindowRect(hwnd, &rcWnd);
        GetClientRect(hwnd, &nmpgScroll.rcParent);
777 778 779
        nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
        nmpgScroll.iDir = dir;

780 781
        if (PAGER_IsHorizontal(hwnd))
        {
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 800
            infoPtr->direction = dir;

801 802 803 804
            if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
                PAGER_SetPos(hwnd, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
            else
                PAGER_SetPos(hwnd, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
805
        }
806 807
        else
            infoPtr->direction = -1;
808
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
809 810
}

811 812 813 814 815 816
static LRESULT
PAGER_FmtLines(HWND hwnd)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);

    /* initiate NCCalcSize to resize client wnd and get size */
817
    SetWindowPos(hwnd, 0, 0,0,0,0,
818 819 820
		 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
		 SWP_NOZORDER | SWP_NOACTIVATE);

821 822
    SetWindowPos(infoPtr->hwndChild, 0,
		 0,0,infoPtr->nWidth,infoPtr->nHeight,
823 824 825 826 827
		 0);

    return DefWindowProcA (hwnd, EM_FMTLINES, 0, 0);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
828
static LRESULT
829
PAGER_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
830 831
{
    PAGER_INFO *infoPtr;
832
    DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
833

Alexandre Julliard's avatar
Alexandre Julliard committed
834
    /* allocate memory for info structure */
Alexandre Julliard's avatar
Alexandre Julliard committed
835
    infoPtr = (PAGER_INFO *)COMCTL32_Alloc (sizeof(PAGER_INFO));
836
    SetWindowLongA (hwnd, 0, (DWORD)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
837 838

    /* set default settings */
839
    infoPtr->hwndChild = (HWND)NULL;
840
    infoPtr->bNoResize = dwStyle & CCS_NORESIZE;
841
    infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
Alexandre Julliard's avatar
Alexandre Julliard committed
842
    infoPtr->nBorder = 0;
843
    infoPtr->nButtonSize = 12;
Alexandre Julliard's avatar
Alexandre Julliard committed
844
    infoPtr->nPos = 0;
845 846 847
    infoPtr->nWidth = 0;
    infoPtr->nHeight = 0;
    infoPtr->bForward = FALSE;
848
    infoPtr->bCapture = FALSE;
849 850
    infoPtr->TLbtnState = PGF_INVISIBLE;
    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 857 858 859 860
    /*
	 * If neither horizontal nor vertical style specified, default to vertical.
	 * This is probably not necessary, since the style may be set later on as
	 * the control is initialized, but just in case it isn't, set it here.
	 */
    if (!(dwStyle & PGS_HORZ) && !(dwStyle & PGS_VERT))
861
    {
862
        dwStyle |= PGS_VERT;
863 864
        SetWindowLongA(hwnd, GWL_STYLE, dwStyle);
    }
865

Alexandre Julliard's avatar
Alexandre Julliard committed
866 867 868 869 870
    return 0;
}


static LRESULT
871
PAGER_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
872
{
873
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
874 875 876 877 878
    /* free pager info data */
    COMCTL32_Free (infoPtr);
    SetWindowLongA (hwnd, 0, 0);
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
879

880 881 882
static LRESULT
PAGER_NCCalcSize(HWND hwnd, WPARAM wParam, LPARAM lParam)
{
883 884
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
    LPRECT lpRect = (LPRECT)lParam;
885
    RECT rcChildw, rcmyw, wnrc, ltrc, rbrc;
886
    POINT cursor;
887 888 889
    BOOL resizeClient = FALSE;
    BOOL repaintBtns = FALSE;
    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 895 896
     * On exit, the struct should contain the screen
     * coordinates of the corresponding window's client area.
     */
897

898 899
    DefWindowProcA (hwnd, WM_NCCALCSIZE, wParam, lParam);

900 901 902
    TRACE("orig rect=(%d,%d)-(%d,%d)\n",
	  lpRect->left, lpRect->top, lpRect->right, lpRect->bottom);

903
    if (PAGER_IsHorizontal(hwnd))
904
    {
905 906 907 908 909 910
	infoPtr->nWidth = lpRect->right - lpRect->left;
	PAGER_CalcSize (hwnd, &infoPtr->nWidth, TRUE);
	GetWindowRect (infoPtr->hwndChild, &rcChildw);
	MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
	GetCursorPos (&cursor);
	GetWindowRect (hwnd, &rcmyw);
911 912

	/* Reset buttons and hide any grey ones */
913
	scrollRange = infoPtr->nWidth - (rcmyw.right - rcmyw.left);
914

915 916 917 918 919
	TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%d,%d)-(%d,%d), cursor=(%ld,%ld)\n",
	      infoPtr->nPos, scrollRange, infoPtr->nHeight,
	      rcmyw.left, rcmyw.top,
	      rcmyw.right, rcmyw.bottom,
	      cursor.x, cursor.y);
920 921 922
	PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
	PAGER_HideGrayBtns(infoPtr, &resizeClient);

923 924
	if (PtInRect (&rcmyw, cursor)) {
	    GetWindowRect (hwnd, &wnrc);
925 926
	    ltrc = wnrc;
	    ltrc.right = ltrc.left + infoPtr->nButtonSize;
927 928
	    rbrc = wnrc;
	    rbrc.left = rbrc.right - infoPtr->nButtonSize;
929 930
	    TRACE("horz lt rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
		  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 934 935 936
		RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
	    if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
		RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
	}
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 943
    }
    else
    {
944
	/* native does: (from trace of IE4 opening "Favorites" frame)
945 946 947 948 949 950 951 952 953 954 955 956 957 958 959
	 *        DefWindowProc
	 *        WM_NOITFY  PGN_CALCSIZE w/ dwFlag=2
	 *        GetWindowRect (child, &rc)
         *        MapWindowPoints (0, syspager, &rc, 2)
         *        GetCursorPos( &cur )
         *        GetWindowRect (syspager, &rc2)
         *        PtInRect (&rc2, cur.x, cur.y) rtns 0
         *        returns with rect empty
	 */
	infoPtr->nHeight = lpRect->bottom - lpRect->top;
	PAGER_CalcSize (hwnd, &infoPtr->nHeight, FALSE);
	GetWindowRect (infoPtr->hwndChild, &rcChildw);
	MapWindowPoints (0, hwnd, (LPPOINT)&rcChildw, 2);
	GetCursorPos (&cursor);
	GetWindowRect (hwnd, &rcmyw);
960 961 962 963

	/* Reset buttons and hide any grey ones */
	scrollRange = infoPtr->nHeight - (rcmyw.bottom - rcmyw.top);

964
	TRACE("nPos=%d, scrollrange=%d, nHeigth=%d, myw=(%d,%d)-(%d,%d), cursor=(%ld,%ld)\n",
965 966
	      infoPtr->nPos, scrollRange, infoPtr->nHeight,
	      rcmyw.left, rcmyw.top,
967 968
	      rcmyw.right, rcmyw.bottom,
	      cursor.x, cursor.y);
969 970 971
	PAGER_GrayAndRestoreBtns(infoPtr, scrollRange, &resizeClient, &repaintBtns);
	PAGER_HideGrayBtns(infoPtr, &resizeClient);

972 973 974 975 976 977 978 979 980 981 982 983 984
	if (PtInRect (&rcmyw, cursor)) {

	    /* native does:
	     *    GetWindowRect(pager, &rc)
	     *    PtInRect(btn-left????, cur.x, cur.y)
	     *    if true -> ???
	     *    PtInRect(btn-right????, cur.x, cur.y)
	     *    if true
	     *      RedrawWindow(pager, 0, 0, 5)
	     *      return TRUE
	     */

	    GetWindowRect (hwnd, &wnrc);
985 986
	    ltrc = wnrc;
	    ltrc.right = ltrc.left + infoPtr->nButtonSize;
987 988
	    rbrc = wnrc;
	    rbrc.left = rbrc.right - infoPtr->nButtonSize;
989 990
	    TRACE("vert lt rect=(%d,%d)-(%d,%d), rb rect=(%d,%d)-(%d,%d)\n",
		  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 994 995 996
		RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
	    if (PtInRect (&rbrc, cursor) && infoPtr->BRbtnState)
		RedrawWindow (hwnd, 0, 0, RDW_INVALIDATE | RDW_ERASE);
	}
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 1001 1002 1003
	    lpRect->bottom -= infoPtr->nButtonSize;
	/* ???? */
	if ((lpRect->bottom < 0) || (lpRect->bottom > infoPtr->nHeight))
	    lpRect->bottom = infoPtr->nHeight;
1004
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1005

1006
    TRACE("[%p] client rect set to %dx%d at (%d,%d) BtnState[%d,%d]\n",
1007 1008 1009
	  hwnd, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top,
	  lpRect->left, lpRect->top,
	  infoPtr->TLbtnState, infoPtr->BRbtnState);
Alexandre Julliard's avatar
Alexandre Julliard committed
1010

1011 1012
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1013

1014 1015 1016 1017 1018 1019 1020
static LRESULT
PAGER_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    PAGER_INFO* infoPtr = PAGER_GetInfoPtr(hwnd);
    DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
    RECT rcWindow, rcBottomRight, rcTopLeft;
    HDC hdc;
1021
    BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034

    if (dwStyle & WS_MINIMIZE)
        return 0;

    DefWindowProcA (hwnd, WM_NCPAINT, wParam, lParam);

    if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW)))
        return 0;

    GetWindowRect (hwnd, &rcWindow);
    OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top);

    rcTopLeft = rcBottomRight = rcWindow;
1035
    if (bHorizontal)
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
    {
        rcTopLeft.right = rcTopLeft.left + infoPtr->nButtonSize;
        rcBottomRight.left = rcBottomRight.right - infoPtr->nButtonSize;
    }
    else
    {
        rcTopLeft.bottom = rcTopLeft.top + infoPtr->nButtonSize;
        rcBottomRight.top = rcBottomRight.bottom - infoPtr->nButtonSize;
    }

    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 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1052 1053 1054
    return 0;
}

1055
static INT
1056 1057 1058 1059
PAGER_HitTest (HWND hwnd, LPPOINT pt)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
    RECT clientRect;
1060
    BOOL bHorizontal = PAGER_IsHorizontal(hwnd);
1061 1062 1063 1064 1065

    GetClientRect (hwnd, &clientRect);

    if (PtInRect(&clientRect, *pt))
    {
1066
        TRACE("HTCLIENT\n");
1067 1068 1069 1070 1071
        return HTCLIENT;
    }

    if (infoPtr->TLbtnState && infoPtr->TLbtnState != PGF_GRAYED)
    {
1072
        if (bHorizontal)
1073 1074 1075
        {
            if (pt->x < clientRect.left)
            {
1076
                TRACE("HTLEFT\n");
1077 1078 1079 1080 1081 1082 1083
                return HTLEFT;
            }
        }
        else
        {
            if (pt->y < clientRect.top)
            {
1084
                TRACE("HTTOP\n");
1085 1086 1087 1088 1089 1090 1091
                return HTTOP;
            }
        }
    }

    if (infoPtr->BRbtnState && infoPtr->BRbtnState != PGF_GRAYED)
    {
1092
        if (bHorizontal)
1093 1094 1095
        {
            if (pt->x > clientRect.right)
            {
1096
                TRACE("HTRIGHT\n");
1097 1098 1099 1100 1101 1102 1103
                return HTRIGHT;
            }
        }
        else
        {
            if (pt->y > clientRect.bottom)
            {
1104
                TRACE("HTBOTTOM\n");
1105 1106 1107 1108 1109
                return HTBOTTOM;
            }
        }
    }

1110
    TRACE("HTNOWHERE\n");
1111 1112 1113 1114 1115 1116
    return HTNOWHERE;
}

static LRESULT
PAGER_NCHitTest (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
1117 1118 1119 1120 1121
    POINT pt;

    pt.x = SLOWORD(lParam);
    pt.y = SHIWORD(lParam);

1122 1123 1124
    ScreenToClient (hwnd, &pt);
    return PAGER_HitTest(hwnd, &pt);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1125 1126

static LRESULT
1127
PAGER_SetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1128
{
1129
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1130
    BOOL notCaptured = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131

1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
    switch(LOWORD(lParam))
    {
        case HTLEFT:
        case HTTOP:
            if ((notCaptured = infoPtr->TLbtnState != PGF_HOT))
                infoPtr->TLbtnState = PGF_HOT;
            break;
        case HTRIGHT:
        case HTBOTTOM:
            if ((notCaptured = infoPtr->BRbtnState != PGF_HOT))
               infoPtr->BRbtnState = PGF_HOT;
            break;
        default:
            return FALSE;
    }

    if (notCaptured)
    {
1150
	PAGER_CaptureandTrack(infoPtr, hwnd);
1151

1152
        SendMessageA(hwnd, WM_NCPAINT, 0, 0);
1153 1154 1155
    }

    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1156 1157
}

1158 1159 1160 1161 1162
static LRESULT
PAGER_MouseLeave (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);

1163 1164 1165
    KillTimer (hwnd, TIMERID1);
    KillTimer (hwnd, TIMERID2);

1166
    TRACE("[%p] ReleaseCapture\n", hwnd);
1167
    ReleaseCapture();
1168
    infoPtr->bCapture = FALSE;
1169 1170 1171 1172 1173 1174 1175 1176

    /* Notify parent of released mouse capture */
    {
        NMHDR nmhdr;
        ZeroMemory (&nmhdr, sizeof (NMHDR));
        nmhdr.hwndFrom = hwnd;
        nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
        nmhdr.code = NM_RELEASEDCAPTURE;
1177
        SendMessageA (GetParent(hwnd), WM_NOTIFY,
1178 1179 1180 1181 1182 1183 1184 1185
                        (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
    }

    /* make HOT btns NORMAL and hide gray btns */
    PAGER_UpdateBtns(hwnd, infoPtr, -1, TRUE);

    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1186

1187 1188 1189 1190
static LRESULT
PAGER_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1191
    POINT clpt, pt;
1192 1193 1194 1195 1196 1197 1198
    RECT wnrect, TLbtnrect, BRbtnrect, *btnrect = NULL;
    DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
    BOOL topLeft = FALSE;
    INT btnstate = 0;
    INT hit;
    HDC hdc;

1199 1200 1201
    pt.x = SLOWORD(lParam);
    pt.y = SHIWORD(lParam);

1202
    TRACE("[%p] to (%ld,%ld)\n", hwnd, pt.x, pt.y);
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
    ClientToScreen(hwnd, &pt);
    GetWindowRect(hwnd, &wnrect);
    if (PtInRect(&wnrect, pt)) {
	TLbtnrect = wnrect;
	BRbtnrect = wnrect;
	if (dwStyle & PGS_HORZ) {
	    TLbtnrect.right = TLbtnrect.left + infoPtr->nButtonSize;
	    BRbtnrect.left = BRbtnrect.right - infoPtr->nButtonSize;
	}
	else {
	    TLbtnrect.bottom = TLbtnrect.top + infoPtr->nButtonSize;
	    BRbtnrect.top = BRbtnrect.bottom - infoPtr->nButtonSize;
	}

	clpt = pt;
	MapWindowPoints(0, hwnd, &clpt, 1);
	hit = PAGER_HitTest(hwnd, &clpt);
	if (hit == HTLEFT || hit == HTTOP) {
	    topLeft = TRUE;
	    btnrect = &TLbtnrect;
	    infoPtr->TLbtnState = PGF_DEPRESSED;
	    btnstate = infoPtr->TLbtnState;
	}
	else if (hit == HTRIGHT || hit == HTBOTTOM) {
	    topLeft = FALSE;
	    btnrect = &BRbtnrect;
	    infoPtr->BRbtnState = PGF_DEPRESSED;
	    btnstate = infoPtr->BRbtnState;
	}

	/* If in one of the buttons the capture and draw buttons */
	if (btnrect) {
1235
	    TRACE("[%p] draw btn (%d,%d)-(%d,%d), Capture %s, style %08lx\n",
1236
		  hwnd, btnrect->left, btnrect->top,
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
		  btnrect->right, btnrect->bottom,
		  (infoPtr->bCapture) ? "TRUE" : "FALSE",
		  dwStyle);
	    if (!infoPtr->bCapture)
		PAGER_CaptureandTrack(infoPtr, hwnd);
	    if (dwStyle & PGS_AUTOSCROLL)
		SetTimer(hwnd, TIMERID1, 0x3e, 0);
	    MapWindowPoints(0, hwnd, (LPPOINT)btnrect, 2);
	    hdc = GetWindowDC(hwnd);
	    /* OffsetRect(wnrect, 0 | 1, 0 | 1) */
	    PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect,
			     PAGER_IsHorizontal(hwnd), topLeft, btnstate);
	    ReleaseDC(hwnd, hdc);
	    return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
	}
    }

    /* If we think we are captured, then do release */
    if (infoPtr->bCapture) {
	infoPtr->bCapture = FALSE;

        if (GetCapture() == hwnd) {
	    ReleaseCapture();
	    /* Notify parent of released mouse capture */
	    {
		NMHDR nmhdr;
		ZeroMemory (&nmhdr, sizeof (NMHDR));
		nmhdr.hwndFrom = hwnd;
		nmhdr.idFrom   = GetWindowLongA (hwnd, GWL_ID);
		nmhdr.code = NM_RELEASEDCAPTURE;
		SendMessageA (GetParent(hwnd), WM_NOTIFY,
			      (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
	    }
	}
	if (IsWindow(hwnd))
	    KillTimer(hwnd, TIMERID1);
    }
    return DefWindowProcA (hwnd, WM_MOUSEMOVE, wParam, lParam);
}

Eric Kohl's avatar
Eric Kohl committed
1277
static LRESULT
1278
PAGER_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
Eric Kohl's avatar
Eric Kohl committed
1279
{
1280 1281
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
    BOOL repaintBtns = FALSE;
1282
    POINT pt;
1283
    INT hit;
Eric Kohl's avatar
Eric Kohl committed
1284

1285 1286 1287
    pt.x = SLOWORD(lParam);
    pt.y = SHIWORD(lParam);

1288
    TRACE("[%p] at (%d,%d)\n", hwnd, SLOWORD(lParam), SHIWORD(lParam));
1289

1290 1291 1292 1293 1294 1295 1296
    hit = PAGER_HitTest(hwnd, &pt);

    /* put btn in DEPRESSED state */
    if (hit == HTLEFT || hit == HTTOP)
    {
        repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
        infoPtr->TLbtnState = PGF_DEPRESSED;
1297
        SetTimer(hwnd, TIMERID1, INITIAL_DELAY, 0);
1298 1299 1300 1301 1302
    }
    else if (hit == HTRIGHT || hit == HTBOTTOM)
    {
        repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
        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 1310 1311

    switch(hit)
    {
    case HTLEFT:
1312
        TRACE("[%p] PGF_SCROLLLEFT\n", hwnd);
1313 1314 1315
        PAGER_Scroll(hwnd, PGF_SCROLLLEFT);
        break;
    case HTTOP:
1316
        TRACE("[%p] PGF_SCROLLUP\n", hwnd);
1317 1318 1319
        PAGER_Scroll(hwnd, PGF_SCROLLUP);
        break;
    case HTRIGHT:
1320
        TRACE("[%p] PGF_SCROLLRIGHT\n", hwnd);
1321 1322 1323
        PAGER_Scroll(hwnd, PGF_SCROLLRIGHT);
        break;
    case HTBOTTOM:
1324
        TRACE("[%p] PGF_SCROLLDOWN\n", hwnd);
1325 1326 1327 1328 1329 1330 1331
        PAGER_Scroll(hwnd, PGF_SCROLLDOWN);
        break;
    default:
        break;
    }

    return TRUE;
Eric Kohl's avatar
Eric Kohl committed
1332 1333
}

1334 1335 1336 1337
static LRESULT
PAGER_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
1338
    TRACE("[%p]\n", hwnd);
Eric Kohl's avatar
Eric Kohl committed
1339

1340 1341 1342
    KillTimer (hwnd, TIMERID1);
    KillTimer (hwnd, TIMERID2);

1343 1344
    /* make PRESSED btns NORMAL but don't hide gray btns */
    PAGER_UpdateBtns(hwnd, infoPtr, -1, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1345

1346 1347
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1348

1349 1350 1351
static LRESULT
PAGER_NCLButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
1352 1353 1354 1355
    POINT pt;

    pt.x = SLOWORD(lParam);
    pt.y = SHIWORD(lParam);
1356

1357
    TRACE("[%p] at (%d,%d)\n", hwnd, SLOWORD(lParam), SHIWORD(lParam));
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
    MapWindowPoints(0, hwnd, &pt, 1);
    lParam = MAKELONG(pt.x, pt.y);
    return PAGER_LButtonDown (hwnd, wParam, lParam);
}

static LRESULT
PAGER_Timer (HWND hwnd, WPARAM wParam)
{
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);
    DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
    INT dir;

    /* if initial timer, kill it and start the repeat timer */
    if (wParam == TIMERID1) {
	if (PAGER_IsHorizontal(hwnd)) {
1373
	    dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1374 1375 1376
		PGF_SCROLLLEFT : PGF_SCROLLRIGHT;
	}
	else {
1377
	    dir = (infoPtr->TLbtnState & PGF_DEPRESSED) ?
1378 1379
		PGF_SCROLLUP : PGF_SCROLLDOWN;
	}
1380
	TRACE("[%p] TIMERID1: style=%08lx, dir=%d\n", hwnd, dwStyle, dir);
1381 1382 1383 1384
	KillTimer(hwnd, TIMERID1);
	SetTimer(hwnd, TIMERID1, REPEAT_DELAY, 0);
	if (dwStyle & PGS_AUTOSCROLL) {
	    PAGER_Scroll(hwnd, dir);
1385
	    SetWindowPos(hwnd, 0,0,0,0,0,
1386 1387 1388 1389 1390 1391 1392
			 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
			 SWP_NOZORDER | SWP_NOACTIVATE);
	}
	return 0;

    }

1393
    TRACE("[%p] TIMERID2: dir=%d\n", hwnd, infoPtr->direction);
1394 1395 1396
    KillTimer(hwnd, TIMERID2);
    if (infoPtr->direction > 0) {
	PAGER_Scroll(hwnd, infoPtr->direction);
1397
	SetTimer(hwnd, TIMERID2, REPEAT_DELAY, 0);
1398 1399 1400 1401
    }
    return 0;
}

1402
static LRESULT
1403
PAGER_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam)
1404
{
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
    POINT pt, ptorig;
    HDC hdc = (HDC)wParam;
    HWND parent;

    /* native does:
     *   parent = GetParent(pager)
     *   pt.x=0; pt.y=0; ?????
     *   MapWindowPoints(pager, parent, &pt, 1)
     *   OffsetWindowOrgEx(hdc, pt.x, pt.y, &ptorg)
     *   SendMessageA(parent, WM_ERASEBKGND, hdc, 0)
     *   SetWindowOrgEx(hdc, 0, 0, 0)
     */

    pt.x = 0;
    pt.y = 0;
    parent = GetParent(hwnd);
    MapWindowPoints(hwnd, parent, &pt, 1);
    OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
    SendMessageA (parent, WM_ERASEBKGND, wParam, lParam);
    SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);


#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 1436 1437 1438 1439 1440 1441

    /* background color of the child should be the same as the pager */
    if (infoPtr->hwndChild)
    {
        GetClientRect (infoPtr->hwndChild, &rect);
        FillRect ((HDC)wParam, &rect, hBrush);
    }

1442
    DeleteObject (hBrush);
1443 1444
#endif

1445 1446 1447 1448
    return TRUE;
}


1449
static LRESULT
1450
PAGER_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1451 1452 1453 1454
{
    /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */

    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

1466
static LRESULT WINAPI
1467
PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1468
{
1469 1470 1471
    PAGER_INFO *infoPtr = PAGER_GetInfoPtr (hwnd);

    if (!infoPtr && (uMsg != WM_CREATE))
1472
	return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1473

Alexandre Julliard's avatar
Alexandre Julliard committed
1474 1475
    switch (uMsg)
    {
1476 1477 1478
        case EM_FMTLINES:
	    return PAGER_FmtLines(hwnd);

1479 1480 1481 1482 1483
        case PGM_FORWARDMOUSE:
            return PAGER_ForwardMouse (hwnd, wParam);

        case PGM_GETBKCOLOR:
            return PAGER_GetBkColor(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1484

1485 1486
        case PGM_GETBORDER:
            return PAGER_GetBorder(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1487

1488 1489
        case PGM_GETBUTTONSIZE:
            return PAGER_GetButtonSize(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1490

1491 1492
        case PGM_GETPOS:
            return PAGER_GetPos(hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
1493

1494 1495
        case PGM_GETBUTTONSTATE:
            return PAGER_GetButtonState (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1496

1497
/*      case PGM_GETDROPTARGET: */
Alexandre Julliard's avatar
Alexandre Julliard committed
1498

1499 1500
        case PGM_RECALCSIZE:
            return PAGER_RecalcSize(hwnd);
1501

1502 1503
        case PGM_SETBKCOLOR:
            return PAGER_SetBkColor (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1504

1505 1506
        case PGM_SETBORDER:
            return PAGER_SetBorder (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1507

1508 1509
        case PGM_SETBUTTONSIZE:
            return PAGER_SetButtonSize (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1510

1511 1512
        case PGM_SETCHILD:
            return PAGER_SetChild (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1513

1514 1515
        case PGM_SETPOS:
            return PAGER_SetPos(hwnd, (INT)lParam, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1516

1517 1518
        case WM_CREATE:
            return PAGER_Create (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1519

1520 1521
        case WM_DESTROY:
            return PAGER_Destroy (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1522

1523
        case WM_SIZE:
1524
            return PAGER_Size (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1525

1526 1527
        case WM_NCPAINT:
            return PAGER_NCPaint (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1528

1529
        case WM_WINDOWPOSCHANGING:
1530
            return PAGER_HandleWindowPosChanging (hwnd, wParam, (WINDOWPOS*)lParam);
1531

1532 1533
        case WM_NCCALCSIZE:
            return PAGER_NCCalcSize (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1534

1535 1536
        case WM_NCHITTEST:
            return PAGER_NCHitTest (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1537

1538 1539 1540 1541 1542 1543 1544
        case WM_SETCURSOR:
        {
            if (hwnd == (HWND)wParam)
                return PAGER_SetCursor(hwnd, wParam, lParam);
            else /* its for the child */
                return 0;
        }
1545

1546 1547 1548
        case WM_MOUSEMOVE:
            if (infoPtr->bForward && infoPtr->hwndChild)
                PostMessageA(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
1549
            return PAGER_MouseMove (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1550

1551
        case WM_MOUSELEAVE:
1552
            return PAGER_MouseLeave (hwnd, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1553

1554 1555 1556
        case WM_NCLBUTTONDOWN:
            return PAGER_NCLButtonDown (hwnd, wParam, lParam);

1557 1558 1559
        case WM_LBUTTONDOWN:
            return PAGER_LButtonDown (hwnd, wParam, lParam);

1560
        case WM_NCLBUTTONUP:
1561 1562 1563 1564 1565 1566 1567
        case WM_LBUTTONUP:
            return PAGER_LButtonUp (hwnd, wParam, lParam);

        case WM_ERASEBKGND:
            return PAGER_EraseBackground (hwnd, wParam, lParam);
/*
        case WM_PAINT:
1568
            return PAGER_Paint (hwnd, wParam);
1569
*/
1570
        case WM_TIMER:
1571
	    return PAGER_Timer (hwnd, wParam);
1572

1573 1574 1575 1576 1577 1578
        case WM_NOTIFY:
        case WM_COMMAND:
            return SendMessageA (GetParent (hwnd), uMsg, wParam, lParam);

        default:
            return DefWindowProcA (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1579
    }
1580

Alexandre Julliard's avatar
Alexandre Julliard committed
1581 1582 1583 1584
    return 0;
}


1585
VOID
1586
PAGER_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1587
{
1588
    WNDCLASSA wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1589

1590
    ZeroMemory (&wndClass, sizeof(WNDCLASSA));
Alexandre Julliard's avatar
Alexandre Julliard committed
1591
    wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
1592
    wndClass.lpfnWndProc   = (WNDPROC)PAGER_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1593 1594
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(PAGER_INFO *);
1595
    wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
Alexandre Julliard's avatar
Alexandre Julliard committed
1596
    wndClass.hbrBackground = 0;
1597
    wndClass.lpszClassName = WC_PAGESCROLLERA;
1598

1599
    RegisterClassA (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
1600 1601
}

1602 1603

VOID
1604
PAGER_Unregister (void)
1605
{
1606
    UnregisterClassA (WC_PAGESCROLLERA, (HINSTANCE)NULL);
1607
}