ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pager.c
Go to the documentation of this file.
00001 /*
00002  * Pager control
00003  *
00004  * Copyright 1998, 1999 Eric Kohl
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  *
00020  * NOTES
00021  *
00022  * This code was audited for completeness against the documented features
00023  * of Comctl32.dll version 6.0 on Sep. 18, 2004, by Robert Shearman.
00024  * 
00025  * Unless otherwise noted, we believe this code to be complete, as per
00026  * the specification mentioned above.
00027  * If you discover missing features or bugs please note them below.
00028  *
00029  * TODO:
00030  *    Implement repetitive button press.
00031  *    Adjust arrow size relative to size of button.
00032  *    Allow border size changes.
00033  *    Styles:
00034  *      PGS_DRAGNDROP
00035  *    Notifications:
00036  *      PGN_HOTITEMCHANGE
00037  *    Messages:
00038  *      WM_PRINT and/or WM_PRINTCLIENT
00039  *
00040  * TESTING:
00041  *    Tested primarily with the controlspy Pager application.
00042  *       Susan Farley (susan@codeweavers.com)
00043  *
00044  * IMPLEMENTATION NOTES:
00045  *    This control uses WM_NCPAINT instead of WM_PAINT to paint itself
00046  *    as we need to scroll a child window. In order to do this we move 
00047  *    the child window in the control's client area, using the clipping
00048  *    region that is automatically set around the client area. As the 
00049  *    entire client area now consists of the child window, we must 
00050  *    allocate space (WM_NCCALCSIZE) for the buttons and draw them as 
00051  *    a non-client area (WM_NCPAINT).
00052  *       Robert Shearman <rob@codeweavers.com>
00053  */
00054 
00055 #include <stdarg.h>
00056 #include <string.h>
00057 #include "windef.h"
00058 #include "winbase.h"
00059 #include "wingdi.h"
00060 #include "winuser.h"
00061 #include "winnls.h"
00062 #include "commctrl.h"
00063 #include "comctl32.h"
00064 #include "wine/debug.h"
00065 
00066 WINE_DEFAULT_DEBUG_CHANNEL(pager);
00067 
00068 typedef struct
00069 {
00070     HWND   hwndSelf;   /* handle of the control wnd */
00071     HWND   hwndChild;  /* handle of the contained wnd */
00072     HWND   hwndNotify; /* handle of the parent wnd */
00073     DWORD  dwStyle;    /* styles for this control */
00074     COLORREF clrBk;    /* background color */
00075     INT    nBorder;    /* border size for the control */
00076     INT    nButtonSize;/* size of the pager btns */
00077     INT    nPos;       /* scroll position */
00078     INT    nWidth;     /* from child wnd's response to PGN_CALCSIZE */
00079     INT    nHeight;    /* from child wnd's response to PGN_CALCSIZE */
00080     BOOL   bForward;   /* forward WM_MOUSEMOVE msgs to the contained wnd */
00081     BOOL   bCapture;   /* we have captured the mouse  */
00082     INT    TLbtnState; /* state of top or left btn */
00083     INT    BRbtnState; /* state of bottom or right btn */
00084     INT    direction;  /* direction of the scroll, (e.g. PGF_SCROLLUP) */
00085 } PAGER_INFO;
00086 
00087 #define MIN_ARROW_WIDTH  8
00088 #define MIN_ARROW_HEIGHT 5
00089 
00090 #define TIMERID1         1
00091 #define TIMERID2         2
00092 #define INITIAL_DELAY    500
00093 #define REPEAT_DELAY     50
00094 
00095 static void
00096 PAGER_GetButtonRects(const PAGER_INFO* infoPtr, RECT* prcTopLeft, RECT* prcBottomRight, BOOL bClientCoords)
00097 {
00098     RECT rcWindow;
00099     GetWindowRect (infoPtr->hwndSelf, &rcWindow);
00100 
00101     if (bClientCoords)
00102         MapWindowPoints( 0, infoPtr->hwndSelf, (POINT *)&rcWindow, 2 );
00103     else
00104         OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
00105 
00106     *prcTopLeft = *prcBottomRight = rcWindow;
00107     if (infoPtr->dwStyle & PGS_HORZ)
00108     {
00109         prcTopLeft->right = prcTopLeft->left + infoPtr->nButtonSize;
00110         prcBottomRight->left = prcBottomRight->right - infoPtr->nButtonSize;
00111     }
00112     else
00113     {
00114         prcTopLeft->bottom = prcTopLeft->top + infoPtr->nButtonSize;
00115         prcBottomRight->top = prcBottomRight->bottom - infoPtr->nButtonSize;
00116     }
00117 }
00118 
00119 /* the horizontal arrows are:
00120  *
00121  * 01234    01234
00122  * 1  *      *
00123  * 2 **      **
00124  * 3***      ***
00125  * 4***      ***
00126  * 5 **      **
00127  * 6  *      *
00128  * 7
00129  *
00130  */
00131 static void
00132 PAGER_DrawHorzArrow (HDC hdc, RECT r, INT colorRef, BOOL left)
00133 {
00134     INT x, y, w, h;
00135     HPEN hPen, hOldPen;
00136 
00137     w = r.right - r.left + 1;
00138     h = r.bottom - r.top + 1;
00139     if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
00140         return;  /* refuse to draw partial arrow */
00141 
00142     if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
00143     hOldPen = SelectObject ( hdc, hPen );
00144     if (left)
00145     {
00146         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 3;
00147         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
00148         MoveToEx (hdc, x, y, NULL);
00149         LineTo (hdc, x--, y+5); y++;
00150         MoveToEx (hdc, x, y, NULL);
00151         LineTo (hdc, x--, y+3); y++;
00152         MoveToEx (hdc, x, y, NULL);
00153         LineTo (hdc, x, y+1);
00154     }
00155     else
00156     {
00157         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
00158         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
00159         MoveToEx (hdc, x, y, NULL);
00160         LineTo (hdc, x++, y+5); y++;
00161         MoveToEx (hdc, x, y, NULL);
00162         LineTo (hdc, x++, y+3); y++;
00163         MoveToEx (hdc, x, y, NULL);
00164         LineTo (hdc, x, y+1);
00165     }
00166 
00167     SelectObject( hdc, hOldPen );
00168     DeleteObject( hPen );
00169 }
00170 
00171 /* the vertical arrows are:
00172  *
00173  * 01234567    01234567
00174  * 1******        **
00175  * 2 ****        ****
00176  * 3  **        ******
00177  * 4
00178  *
00179  */
00180 static void
00181 PAGER_DrawVertArrow (HDC hdc, RECT r, INT colorRef, BOOL up)
00182 {
00183     INT x, y, w, h;
00184     HPEN hPen, hOldPen;
00185 
00186     w = r.right - r.left + 1;
00187     h = r.bottom - r.top + 1;
00188     if ((h < MIN_ARROW_WIDTH) || (w < MIN_ARROW_HEIGHT))
00189         return;  /* refuse to draw partial arrow */
00190 
00191     if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return;
00192     hOldPen = SelectObject ( hdc, hPen );
00193     if (up)
00194     {
00195         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
00196         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 3;
00197         MoveToEx (hdc, x, y, NULL);
00198         LineTo (hdc, x+5, y--); x++;
00199         MoveToEx (hdc, x, y, NULL);
00200         LineTo (hdc, x+3, y--); x++;
00201         MoveToEx (hdc, x, y, NULL);
00202         LineTo (hdc, x+1, y);
00203     }
00204     else
00205     {
00206         x = r.left + ((w - MIN_ARROW_HEIGHT) / 2) + 1;
00207         y = r.top + ((h - MIN_ARROW_WIDTH) / 2) + 1;
00208         MoveToEx (hdc, x, y, NULL);
00209         LineTo (hdc, x+5, y++); x++;
00210         MoveToEx (hdc, x, y, NULL);
00211         LineTo (hdc, x+3, y++); x++;
00212         MoveToEx (hdc, x, y, NULL);
00213         LineTo (hdc, x+1, y);
00214     }
00215 
00216     SelectObject( hdc, hOldPen );
00217     DeleteObject( hPen );
00218 }
00219 
00220 static void
00221 PAGER_DrawButton(HDC hdc, COLORREF clrBk, RECT arrowRect,
00222                  BOOL horz, BOOL topLeft, INT btnState)
00223 {
00224     HBRUSH   hBrush, hOldBrush;
00225     RECT     rc = arrowRect;
00226 
00227     TRACE("arrowRect = %s, btnState = %d\n", wine_dbgstr_rect(&arrowRect), btnState);
00228 
00229     if (btnState == PGF_INVISIBLE)
00230         return;
00231 
00232     if ((rc.right - rc.left <= 0) || (rc.bottom - rc.top <= 0))
00233         return;
00234 
00235     hBrush = CreateSolidBrush(clrBk);
00236     hOldBrush = SelectObject(hdc, hBrush);
00237 
00238     FillRect(hdc, &rc, hBrush);
00239 
00240     if (btnState == PGF_HOT)
00241     {
00242        DrawEdge( hdc, &rc, BDR_RAISEDINNER, BF_RECT);
00243        if (horz)
00244            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00245        else
00246            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00247     }
00248     else if (btnState == PGF_NORMAL)
00249     {
00250        DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
00251        if (horz)
00252            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00253        else
00254            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00255     }
00256     else if (btnState == PGF_DEPRESSED)
00257     {
00258        DrawEdge( hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
00259        if (horz)
00260            PAGER_DrawHorzArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00261        else
00262            PAGER_DrawVertArrow(hdc, rc, COLOR_WINDOWFRAME, topLeft);
00263     }
00264     else if (btnState == PGF_GRAYED)
00265     {
00266        DrawEdge (hdc, &rc, BDR_OUTER, BF_FLAT);
00267        if (horz)
00268        {
00269            PAGER_DrawHorzArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
00270            rc.left++, rc.top++; rc.right++, rc.bottom++;
00271            PAGER_DrawHorzArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
00272        }
00273        else
00274        {
00275            PAGER_DrawVertArrow(hdc, rc, COLOR_3DHIGHLIGHT, topLeft);
00276            rc.left++, rc.top++; rc.right++, rc.bottom++;
00277            PAGER_DrawVertArrow(hdc, rc, COLOR_3DSHADOW, topLeft);
00278        }
00279     }
00280 
00281     SelectObject( hdc, hOldBrush );
00282     DeleteObject(hBrush);
00283 }
00284 
00285 /* << PAGER_GetDropTarget >> */
00286 
00287 static inline LRESULT
00288 PAGER_ForwardMouse (PAGER_INFO* infoPtr, BOOL bFwd)
00289 {
00290     TRACE("[%p]\n", infoPtr->hwndSelf);
00291 
00292     infoPtr->bForward = bFwd;
00293 
00294     return 0;
00295 }
00296 
00297 static inline LRESULT
00298 PAGER_GetButtonState (const PAGER_INFO* infoPtr, INT btn)
00299 {
00300     LRESULT btnState = PGF_INVISIBLE;
00301     TRACE("[%p]\n", infoPtr->hwndSelf);
00302 
00303     if (btn == PGB_TOPORLEFT)
00304         btnState = infoPtr->TLbtnState;
00305     else if (btn == PGB_BOTTOMORRIGHT)
00306         btnState = infoPtr->BRbtnState;
00307 
00308     return btnState;
00309 }
00310 
00311 
00312 static inline INT
00313 PAGER_GetPos(const PAGER_INFO *infoPtr)
00314 {
00315     TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nPos);
00316     return infoPtr->nPos;
00317 }
00318 
00319 static inline INT
00320 PAGER_GetButtonSize(const PAGER_INFO *infoPtr)
00321 {
00322     TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize);
00323     return infoPtr->nButtonSize;
00324 }
00325 
00326 static inline INT
00327 PAGER_GetBorder(const PAGER_INFO *infoPtr)
00328 {
00329     TRACE("[%p] returns %d\n", infoPtr->hwndSelf, infoPtr->nBorder);
00330     return infoPtr->nBorder;
00331 }
00332 
00333 static inline COLORREF
00334 PAGER_GetBkColor(const PAGER_INFO *infoPtr)
00335 {
00336     TRACE("[%p] returns %06x\n", infoPtr->hwndSelf, infoPtr->clrBk);
00337     return infoPtr->clrBk;
00338 }
00339 
00340 static void
00341 PAGER_CalcSize (const PAGER_INFO *infoPtr, INT* size, BOOL getWidth)
00342 {
00343     NMPGCALCSIZE nmpgcs;
00344     ZeroMemory (&nmpgcs, sizeof (NMPGCALCSIZE));
00345     nmpgcs.hdr.hwndFrom = infoPtr->hwndSelf;
00346     nmpgcs.hdr.idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
00347     nmpgcs.hdr.code = PGN_CALCSIZE;
00348     nmpgcs.dwFlag = getWidth ? PGF_CALCWIDTH : PGF_CALCHEIGHT;
00349     nmpgcs.iWidth = getWidth ? *size : 0;
00350     nmpgcs.iHeight = getWidth ? 0 : *size;
00351     SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, nmpgcs.hdr.idFrom, (LPARAM)&nmpgcs);
00352 
00353     *size = getWidth ? nmpgcs.iWidth : nmpgcs.iHeight;
00354 
00355     TRACE("[%p] PGN_CALCSIZE returns %s=%d\n", infoPtr->hwndSelf,
00356                   getWidth ? "width" : "height", *size);
00357 }
00358 
00359 static void
00360 PAGER_PositionChildWnd(PAGER_INFO* infoPtr)
00361 {
00362     if (infoPtr->hwndChild)
00363     {
00364         RECT rcClient;
00365         int nPos = infoPtr->nPos;
00366 
00367         /* compensate for a grayed btn, which will soon become invisible */
00368         if (infoPtr->TLbtnState == PGF_GRAYED)
00369             nPos += infoPtr->nButtonSize;
00370 
00371         GetClientRect(infoPtr->hwndSelf, &rcClient);
00372 
00373         if (infoPtr->dwStyle & PGS_HORZ)
00374         {
00375             int wndSize = max(0, rcClient.right - rcClient.left);
00376             if (infoPtr->nWidth < wndSize)
00377                 infoPtr->nWidth = wndSize;
00378 
00379             TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf,
00380                          infoPtr->nWidth, infoPtr->nHeight,
00381                          -nPos, 0);
00382             SetWindowPos(infoPtr->hwndChild, 0,
00383                          -nPos, 0,
00384                          infoPtr->nWidth, infoPtr->nHeight,
00385                          SWP_NOZORDER);
00386         }
00387         else
00388         {
00389             int wndSize = max(0, rcClient.bottom - rcClient.top);
00390             if (infoPtr->nHeight < wndSize)
00391                 infoPtr->nHeight = wndSize;
00392 
00393             TRACE("[%p] SWP %dx%d at (%d,%d)\n", infoPtr->hwndSelf,
00394                          infoPtr->nWidth, infoPtr->nHeight,
00395                          0, -nPos);
00396             SetWindowPos(infoPtr->hwndChild, 0,
00397                          0, -nPos,
00398                          infoPtr->nWidth, infoPtr->nHeight,
00399                          SWP_NOZORDER);
00400         }
00401 
00402         InvalidateRect(infoPtr->hwndChild, NULL, TRUE);
00403     }
00404 }
00405 
00406 static INT
00407 PAGER_GetScrollRange(PAGER_INFO* infoPtr)
00408 {
00409     INT scrollRange = 0;
00410 
00411     if (infoPtr->hwndChild)
00412     {
00413         INT wndSize, childSize;
00414         RECT wndRect;
00415         GetWindowRect(infoPtr->hwndSelf, &wndRect);
00416 
00417         if (infoPtr->dwStyle & PGS_HORZ)
00418         {
00419             wndSize = wndRect.right - wndRect.left;
00420             PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE);
00421             childSize = infoPtr->nWidth;
00422         }
00423         else
00424         {
00425             wndSize = wndRect.bottom - wndRect.top;
00426             PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE);
00427             childSize = infoPtr->nHeight;
00428         }
00429 
00430         TRACE("childSize = %d,  wndSize = %d\n", childSize, wndSize);
00431         if (childSize > wndSize)
00432             scrollRange = childSize - wndSize + infoPtr->nButtonSize;
00433     }
00434 
00435     TRACE("[%p] returns %d\n", infoPtr->hwndSelf, scrollRange);
00436     return scrollRange;
00437 }
00438 
00439 static void
00440 PAGER_UpdateBtns(PAGER_INFO *infoPtr, INT scrollRange, BOOL hideGrayBtns)
00441 {
00442     BOOL resizeClient;
00443     BOOL repaintBtns;
00444     INT oldTLbtnState = infoPtr->TLbtnState;
00445     INT oldBRbtnState = infoPtr->BRbtnState;
00446     POINT pt;
00447     RECT rcTopLeft, rcBottomRight;
00448 
00449     /* get button rects */
00450     PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE);
00451 
00452     GetCursorPos(&pt);
00453 
00454     /* update states based on scroll position */
00455     if (infoPtr->nPos > 0)
00456     {
00457         if (infoPtr->TLbtnState == PGF_INVISIBLE || infoPtr->TLbtnState == PGF_GRAYED)
00458             infoPtr->TLbtnState = PGF_NORMAL;
00459     }
00460     else if (PtInRect(&rcTopLeft, pt))
00461         infoPtr->TLbtnState = PGF_GRAYED;
00462     else
00463         infoPtr->TLbtnState = PGF_INVISIBLE;
00464 
00465     if (scrollRange <= 0)
00466     {
00467         infoPtr->TLbtnState = PGF_INVISIBLE;
00468         infoPtr->BRbtnState = PGF_INVISIBLE;
00469     }
00470     else if (infoPtr->nPos < scrollRange)
00471     {
00472         if (infoPtr->BRbtnState == PGF_INVISIBLE || infoPtr->BRbtnState == PGF_GRAYED)
00473             infoPtr->BRbtnState = PGF_NORMAL;
00474     }
00475     else if (PtInRect(&rcBottomRight, pt))
00476         infoPtr->BRbtnState = PGF_GRAYED;
00477     else
00478         infoPtr->BRbtnState = PGF_INVISIBLE;
00479 
00480     /* only need to resize when entering or leaving PGF_INVISIBLE state */
00481     resizeClient =
00482         ((oldTLbtnState == PGF_INVISIBLE) != (infoPtr->TLbtnState == PGF_INVISIBLE)) ||
00483         ((oldBRbtnState == PGF_INVISIBLE) != (infoPtr->BRbtnState == PGF_INVISIBLE));
00484     /* initiate NCCalcSize to resize client wnd if necessary */
00485     if (resizeClient)
00486         SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
00487                      SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
00488                      SWP_NOZORDER | SWP_NOACTIVATE);
00489 
00490     /* repaint when changing any state */
00491     repaintBtns = (oldTLbtnState != infoPtr->TLbtnState) || 
00492                   (oldBRbtnState != infoPtr->BRbtnState);
00493     if (repaintBtns)
00494         SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0);
00495 }
00496 
00497 static LRESULT
00498 PAGER_SetPos(PAGER_INFO* infoPtr, INT newPos, BOOL fromBtnPress)
00499 {
00500     INT scrollRange = PAGER_GetScrollRange(infoPtr);
00501     INT oldPos = infoPtr->nPos;
00502 
00503     if ((scrollRange <= 0) || (newPos < 0))
00504         infoPtr->nPos = 0;
00505     else if (newPos > scrollRange)
00506         infoPtr->nPos = scrollRange;
00507     else
00508         infoPtr->nPos = newPos;
00509 
00510     TRACE("[%p] pos=%d, oldpos=%d\n", infoPtr->hwndSelf, infoPtr->nPos, oldPos);
00511 
00512     if (infoPtr->nPos != oldPos)
00513     {
00514         /* gray and restore btns, and if from WM_SETPOS, hide the gray btns */
00515         PAGER_UpdateBtns(infoPtr, scrollRange, !fromBtnPress);
00516         PAGER_PositionChildWnd(infoPtr);
00517     }
00518 
00519     return 0;
00520 }
00521 
00522 static LRESULT
00523 PAGER_WindowPosChanging(PAGER_INFO* infoPtr, WINDOWPOS *winpos)
00524 {
00525     if ((infoPtr->dwStyle & CCS_NORESIZE) && !(winpos->flags & SWP_NOSIZE))
00526     {
00527         /* don't let the app resize the nonscrollable dimension of a control
00528          * that was created with CCS_NORESIZE style
00529          * (i.e. height for a horizontal pager, or width for a vertical one) */
00530 
00531     /* except if the current dimension is 0 and app is setting for
00532      * first time, then save amount as dimension. - GA 8/01 */
00533 
00534         if (infoPtr->dwStyle & PGS_HORZ)
00535         if (!infoPtr->nHeight && winpos->cy)
00536         infoPtr->nHeight = winpos->cy;
00537         else
00538         winpos->cy = infoPtr->nHeight;
00539         else
00540         if (!infoPtr->nWidth && winpos->cx)
00541         infoPtr->nWidth = winpos->cx;
00542         else
00543         winpos->cx = infoPtr->nWidth;
00544     return 0;
00545     }
00546 
00547     return DefWindowProcW (infoPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)winpos);
00548 }
00549 
00550 static INT
00551 PAGER_SetFixedWidth(PAGER_INFO* infoPtr)
00552 {
00553   /* Must set the non-scrollable dimension to be less than the full height/width
00554    * so that NCCalcSize is called.  The Microsoft docs mention 3/4 factor for button
00555    * size, and experimentation shows that the effect is almost right. */
00556 
00557     RECT wndRect;
00558     INT delta, h;
00559     GetWindowRect(infoPtr->hwndSelf, &wndRect);
00560 
00561     /* see what the app says for btn width */
00562     PAGER_CalcSize(infoPtr, &infoPtr->nWidth, TRUE);
00563 
00564     if (infoPtr->dwStyle & CCS_NORESIZE)
00565     {
00566         delta = wndRect.right - wndRect.left - infoPtr->nWidth;
00567         if (delta > infoPtr->nButtonSize)
00568             infoPtr->nWidth += 4 * infoPtr->nButtonSize / 3;
00569         else if (delta > 0)
00570             infoPtr->nWidth +=  infoPtr->nButtonSize / 3;
00571     }
00572 
00573     h = wndRect.bottom - wndRect.top + infoPtr->nButtonSize;
00574 
00575     TRACE("[%p] infoPtr->nWidth set to %d\n",
00576            infoPtr->hwndSelf, infoPtr->nWidth);
00577 
00578     return h;
00579 }
00580 
00581 static INT
00582 PAGER_SetFixedHeight(PAGER_INFO* infoPtr)
00583 {
00584   /* Must set the non-scrollable dimension to be less than the full height/width
00585    * so that NCCalcSize is called.  The Microsoft docs mention 3/4 factor for button
00586    * size, and experimentation shows that the effect is almost right. */
00587 
00588     RECT wndRect;
00589     INT delta, w;
00590     GetWindowRect(infoPtr->hwndSelf, &wndRect);
00591 
00592     /* see what the app says for btn height */
00593     PAGER_CalcSize(infoPtr, &infoPtr->nHeight, FALSE);
00594 
00595     if (infoPtr->dwStyle & CCS_NORESIZE)
00596     {
00597         delta = wndRect.bottom - wndRect.top - infoPtr->nHeight;
00598         if (delta > infoPtr->nButtonSize)
00599             infoPtr->nHeight += infoPtr->nButtonSize;
00600         else if (delta > 0)
00601             infoPtr->nHeight +=  infoPtr->nButtonSize / 3;
00602     }
00603 
00604     w = wndRect.right - wndRect.left + infoPtr->nButtonSize;
00605 
00606     TRACE("[%p] infoPtr->nHeight set to %d\n",
00607            infoPtr->hwndSelf, infoPtr->nHeight);
00608 
00609     return w;
00610 }
00611 
00612 /******************************************************************
00613  * For the PGM_RECALCSIZE message (but not the other uses in      *
00614  * this module), the native control does only the following:      *
00615  *                                                                *
00616  *    if (some condition)                                         *
00617  *          PostMessageW(hwnd, EM_FMTLINES, 0, 0);                *
00618  *    return DefWindowProcW(hwnd, PGM_RECALCSIZE, 0, 0);          *
00619  *                                                                *
00620  * When we figure out what the "some condition" is we will        *
00621  * implement that for the message processing.                     *
00622  ******************************************************************/
00623 
00624 static LRESULT
00625 PAGER_RecalcSize(PAGER_INFO *infoPtr)
00626 {
00627     TRACE("[%p]\n", infoPtr->hwndSelf);
00628 
00629     if (infoPtr->hwndChild)
00630     {
00631         INT scrollRange = PAGER_GetScrollRange(infoPtr);
00632 
00633         if (scrollRange <= 0)
00634         {
00635             infoPtr->nPos = -1;
00636             PAGER_SetPos(infoPtr, 0, FALSE);
00637         }
00638         else
00639             PAGER_PositionChildWnd(infoPtr);
00640     }
00641 
00642     return 1;
00643 }
00644 
00645 
00646 static COLORREF
00647 PAGER_SetBkColor (PAGER_INFO* infoPtr, COLORREF clrBk)
00648 {
00649     COLORREF clrTemp = infoPtr->clrBk;
00650 
00651     infoPtr->clrBk = clrBk;
00652     TRACE("[%p] %06x\n", infoPtr->hwndSelf, infoPtr->clrBk);
00653 
00654     /* the native control seems to do things this way */
00655     SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
00656          SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
00657          SWP_NOZORDER | SWP_NOACTIVATE);
00658 
00659     RedrawWindow(infoPtr->hwndSelf, 0, 0, RDW_ERASE | RDW_INVALIDATE);
00660 
00661     return clrTemp;
00662 }
00663 
00664 
00665 static INT
00666 PAGER_SetBorder (PAGER_INFO* infoPtr, INT iBorder)
00667 {
00668     INT nTemp = infoPtr->nBorder;
00669 
00670     infoPtr->nBorder = iBorder;
00671     TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nBorder);
00672 
00673     PAGER_RecalcSize(infoPtr);
00674 
00675     return nTemp;
00676 }
00677 
00678 
00679 static INT
00680 PAGER_SetButtonSize (PAGER_INFO* infoPtr, INT iButtonSize)
00681 {
00682     INT nTemp = infoPtr->nButtonSize;
00683 
00684     infoPtr->nButtonSize = iButtonSize;
00685     TRACE("[%p] %d\n", infoPtr->hwndSelf, infoPtr->nButtonSize);
00686 
00687     PAGER_RecalcSize(infoPtr);
00688 
00689     return nTemp;
00690 }
00691 
00692 
00693 static LRESULT
00694 PAGER_SetChild (PAGER_INFO* infoPtr, HWND hwndChild)
00695 {
00696     INT hw;
00697 
00698     infoPtr->hwndChild = IsWindow (hwndChild) ? hwndChild : 0;
00699 
00700     if (infoPtr->hwndChild)
00701     {
00702         TRACE("[%p] hwndChild=%p\n", infoPtr->hwndSelf, infoPtr->hwndChild);
00703 
00704         if (infoPtr->dwStyle & PGS_HORZ) {
00705             hw = PAGER_SetFixedHeight(infoPtr);
00706         /* adjust non-scrollable dimension to fit the child */
00707         SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, hw, infoPtr->nHeight,
00708              SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
00709              SWP_NOSIZE | SWP_NOACTIVATE);
00710     }
00711         else {
00712             hw = PAGER_SetFixedWidth(infoPtr);
00713         /* adjust non-scrollable dimension to fit the child */
00714         SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, infoPtr->nWidth, hw,
00715              SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOZORDER |
00716              SWP_NOSIZE | SWP_NOACTIVATE);
00717     }
00718 
00719         /* position child within the page scroller */
00720         SetWindowPos(infoPtr->hwndChild, HWND_TOP,
00721                      0,0,0,0,
00722                      SWP_SHOWWINDOW | SWP_NOSIZE);  /* native is 0 */
00723 
00724         infoPtr->nPos = -1;
00725         PAGER_SetPos(infoPtr, 0, FALSE);
00726     }
00727 
00728     return 0;
00729 }
00730 
00731 static void
00732 PAGER_Scroll(PAGER_INFO* infoPtr, INT dir)
00733 {
00734     NMPGSCROLL nmpgScroll;
00735     RECT rcWnd;
00736 
00737     if (infoPtr->hwndChild)
00738     {
00739         ZeroMemory (&nmpgScroll, sizeof (NMPGSCROLL));
00740         nmpgScroll.hdr.hwndFrom = infoPtr->hwndSelf;
00741         nmpgScroll.hdr.idFrom   = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
00742         nmpgScroll.hdr.code = PGN_SCROLL;
00743 
00744         GetWindowRect(infoPtr->hwndSelf, &rcWnd);
00745         GetClientRect(infoPtr->hwndSelf, &nmpgScroll.rcParent);
00746         nmpgScroll.iXpos = nmpgScroll.iYpos = 0;
00747         nmpgScroll.iDir = dir;
00748 
00749         if (infoPtr->dwStyle & PGS_HORZ)
00750         {
00751             nmpgScroll.iScroll = rcWnd.right - rcWnd.left;
00752             nmpgScroll.iXpos = infoPtr->nPos;
00753         }
00754         else
00755         {
00756             nmpgScroll.iScroll = rcWnd.bottom - rcWnd.top;
00757             nmpgScroll.iYpos = infoPtr->nPos;
00758         }
00759         nmpgScroll.iScroll -= 2*infoPtr->nButtonSize;
00760 
00761         SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, nmpgScroll.hdr.idFrom, (LPARAM)&nmpgScroll);
00762 
00763         TRACE("[%p] PGN_SCROLL returns iScroll=%d\n", infoPtr->hwndSelf, nmpgScroll.iScroll);
00764 
00765         if (nmpgScroll.iScroll > 0)
00766         {
00767             infoPtr->direction = dir;
00768 
00769             if (dir == PGF_SCROLLLEFT || dir == PGF_SCROLLUP)
00770                 PAGER_SetPos(infoPtr, infoPtr->nPos - nmpgScroll.iScroll, TRUE);
00771             else
00772                 PAGER_SetPos(infoPtr, infoPtr->nPos + nmpgScroll.iScroll, TRUE);
00773         }
00774         else
00775             infoPtr->direction = -1;
00776     }
00777 }
00778 
00779 static LRESULT
00780 PAGER_FmtLines(const PAGER_INFO *infoPtr)
00781 {
00782     /* initiate NCCalcSize to resize client wnd and get size */
00783     SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
00784          SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
00785          SWP_NOZORDER | SWP_NOACTIVATE);
00786 
00787     SetWindowPos(infoPtr->hwndChild, 0,
00788          0,0,infoPtr->nWidth,infoPtr->nHeight,
00789          0);
00790 
00791     return DefWindowProcW (infoPtr->hwndSelf, EM_FMTLINES, 0, 0);
00792 }
00793 
00794 static LRESULT
00795 PAGER_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
00796 {
00797     PAGER_INFO *infoPtr;
00798 
00799     /* allocate memory for info structure */
00800     infoPtr = Alloc (sizeof(PAGER_INFO));
00801     if (!infoPtr) return -1;
00802     SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
00803 
00804     /* set default settings */
00805     infoPtr->hwndSelf = hwnd;
00806     infoPtr->hwndChild = NULL;
00807     infoPtr->hwndNotify = lpcs->hwndParent;
00808     infoPtr->dwStyle = lpcs->style;
00809     infoPtr->clrBk = GetSysColor(COLOR_BTNFACE);
00810     infoPtr->nBorder = 0;
00811     infoPtr->nButtonSize = 12;
00812     infoPtr->nPos = 0;
00813     infoPtr->nWidth = 0;
00814     infoPtr->nHeight = 0;
00815     infoPtr->bForward = FALSE;
00816     infoPtr->bCapture = FALSE;
00817     infoPtr->TLbtnState = PGF_INVISIBLE;
00818     infoPtr->BRbtnState = PGF_INVISIBLE;
00819     infoPtr->direction = -1;
00820 
00821     if (infoPtr->dwStyle & PGS_DRAGNDROP)
00822         FIXME("[%p] Drag and Drop style is not implemented yet.\n", infoPtr->hwndSelf);
00823 
00824     return 0;
00825 }
00826 
00827 
00828 static LRESULT
00829 PAGER_Destroy (PAGER_INFO *infoPtr)
00830 {
00831     SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
00832     Free (infoPtr);  /* free pager info data */
00833     return 0;
00834 }
00835 
00836 static LRESULT
00837 PAGER_NCCalcSize(PAGER_INFO* infoPtr, WPARAM wParam, LPRECT lpRect)
00838 {
00839     RECT rcChild, rcWindow;
00840 
00841     /*
00842      * lpRect points to a RECT struct.  On entry, the struct
00843      * contains the proposed wnd rectangle for the window.
00844      * On exit, the struct should contain the screen
00845      * coordinates of the corresponding window's client area.
00846      */
00847 
00848     DefWindowProcW (infoPtr->hwndSelf, WM_NCCALCSIZE, wParam, (LPARAM)lpRect);
00849 
00850     TRACE("orig rect=%s\n", wine_dbgstr_rect(lpRect));
00851 
00852     GetWindowRect (infoPtr->hwndChild, &rcChild);
00853     MapWindowPoints (0, infoPtr->hwndSelf, (LPPOINT)&rcChild, 2); /* FIXME: RECT != 2 POINTS */
00854     GetWindowRect (infoPtr->hwndSelf, &rcWindow);
00855 
00856     if (infoPtr->dwStyle & PGS_HORZ)
00857     {
00858     infoPtr->nWidth = lpRect->right - lpRect->left;
00859     PAGER_CalcSize (infoPtr, &infoPtr->nWidth, TRUE);
00860 
00861     if (infoPtr->TLbtnState && (lpRect->left + infoPtr->nButtonSize < lpRect->right))
00862         lpRect->left += infoPtr->nButtonSize;
00863     if (infoPtr->BRbtnState && (lpRect->right - infoPtr->nButtonSize > lpRect->left))
00864         lpRect->right -= infoPtr->nButtonSize;
00865     }
00866     else
00867     {
00868     infoPtr->nHeight = lpRect->bottom - lpRect->top;
00869     PAGER_CalcSize (infoPtr, &infoPtr->nHeight, FALSE);
00870 
00871     if (infoPtr->TLbtnState && (lpRect->top + infoPtr->nButtonSize < lpRect->bottom))
00872         lpRect->top += infoPtr->nButtonSize;
00873     if (infoPtr->BRbtnState && (lpRect->bottom - infoPtr->nButtonSize > lpRect->top))
00874         lpRect->bottom -= infoPtr->nButtonSize;
00875     }
00876 
00877     TRACE("nPos=%d, nHeight=%d, window=%s\n",
00878           infoPtr->nPos, infoPtr->nHeight,
00879           wine_dbgstr_rect(&rcWindow));
00880 
00881     TRACE("[%p] client rect set to %dx%d at (%d,%d) BtnState[%d,%d]\n",
00882       infoPtr->hwndSelf, lpRect->right-lpRect->left, lpRect->bottom-lpRect->top,
00883       lpRect->left, lpRect->top,
00884       infoPtr->TLbtnState, infoPtr->BRbtnState);
00885 
00886     return 0;
00887 }
00888 
00889 static LRESULT
00890 PAGER_NCPaint (const PAGER_INFO* infoPtr, HRGN hRgn)
00891 {
00892     RECT rcBottomRight, rcTopLeft;
00893     HDC hdc;
00894 
00895     if (infoPtr->dwStyle & WS_MINIMIZE)
00896         return 0;
00897 
00898     DefWindowProcW (infoPtr->hwndSelf, WM_NCPAINT, (WPARAM)hRgn, 0);
00899 
00900     if (!(hdc = GetDCEx (infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW)))
00901         return 0;
00902 
00903     PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, FALSE);
00904 
00905     PAGER_DrawButton(hdc, infoPtr->clrBk, rcTopLeft,
00906                      infoPtr->dwStyle & PGS_HORZ, TRUE, infoPtr->TLbtnState);
00907     PAGER_DrawButton(hdc, infoPtr->clrBk, rcBottomRight,
00908                      infoPtr->dwStyle & PGS_HORZ, FALSE, infoPtr->BRbtnState);
00909 
00910     ReleaseDC( infoPtr->hwndSelf, hdc );
00911     return 0;
00912 }
00913 
00914 static INT
00915 PAGER_HitTest (const PAGER_INFO* infoPtr, const POINT * pt)
00916 {
00917     RECT clientRect, rcTopLeft, rcBottomRight;
00918     POINT ptWindow;
00919 
00920     GetClientRect (infoPtr->hwndSelf, &clientRect);
00921 
00922     if (PtInRect(&clientRect, *pt))
00923     {
00924         TRACE("child\n");
00925         return -1;
00926     }
00927 
00928     ptWindow = *pt;
00929     PAGER_GetButtonRects(infoPtr, &rcTopLeft, &rcBottomRight, TRUE);
00930 
00931     if ((infoPtr->TLbtnState != PGF_INVISIBLE) && PtInRect(&rcTopLeft, ptWindow))
00932     {
00933         TRACE("PGB_TOPORLEFT\n");
00934         return PGB_TOPORLEFT;
00935     }
00936     else if ((infoPtr->BRbtnState != PGF_INVISIBLE) && PtInRect(&rcBottomRight, ptWindow))
00937     {
00938         TRACE("PGB_BOTTOMORRIGHT\n");
00939         return PGB_BOTTOMORRIGHT;
00940     }
00941 
00942     TRACE("nowhere\n");
00943     return -1;
00944 }
00945 
00946 static LRESULT
00947 PAGER_NCHitTest (const PAGER_INFO* infoPtr, INT x, INT y)
00948 {
00949     POINT pt;
00950     INT nHit;
00951 
00952     pt.x = x;
00953     pt.y = y;
00954 
00955     ScreenToClient (infoPtr->hwndSelf, &pt);
00956     nHit = PAGER_HitTest(infoPtr, &pt);
00957 
00958     return (nHit < 0) ? HTTRANSPARENT : HTCLIENT;
00959 }
00960 
00961 static LRESULT
00962 PAGER_MouseMove (PAGER_INFO* infoPtr, INT keys, INT x, INT y)
00963 {
00964     POINT clpt, pt;
00965     RECT wnrect, *btnrect = NULL;
00966     BOOL topLeft = FALSE;
00967     INT btnstate = 0;
00968     INT hit;
00969     HDC hdc;
00970 
00971     pt.x = x;
00972     pt.y = y;
00973 
00974     TRACE("[%p] to (%d,%d)\n", infoPtr->hwndSelf, x, y);
00975     ClientToScreen(infoPtr->hwndSelf, &pt);
00976     GetWindowRect(infoPtr->hwndSelf, &wnrect);
00977     if (PtInRect(&wnrect, pt)) {
00978         RECT TLbtnrect, BRbtnrect;
00979         PAGER_GetButtonRects(infoPtr, &TLbtnrect, &BRbtnrect, FALSE);
00980 
00981     clpt = pt;
00982     MapWindowPoints(0, infoPtr->hwndSelf, &clpt, 1);
00983     hit = PAGER_HitTest(infoPtr, &clpt);
00984     if ((hit == PGB_TOPORLEFT) && (infoPtr->TLbtnState == PGF_NORMAL))
00985     {
00986         topLeft = TRUE;
00987         btnrect = &TLbtnrect;
00988         infoPtr->TLbtnState = PGF_HOT;
00989         btnstate = infoPtr->TLbtnState;
00990     }
00991     else if ((hit == PGB_BOTTOMORRIGHT) && (infoPtr->BRbtnState == PGF_NORMAL))
00992     {
00993         topLeft = FALSE;
00994         btnrect = &BRbtnrect;
00995         infoPtr->BRbtnState = PGF_HOT;
00996         btnstate = infoPtr->BRbtnState;
00997     }
00998 
00999     /* If in one of the buttons the capture and draw buttons */
01000     if (btnrect)
01001     {
01002             TRACE("[%p] draw btn (%s), Capture %s, style %08x\n",
01003                   infoPtr->hwndSelf, wine_dbgstr_rect(btnrect),
01004           (infoPtr->bCapture) ? "TRUE" : "FALSE",
01005           infoPtr->dwStyle);
01006         if (!infoPtr->bCapture)
01007         {
01008             TRACE("[%p] SetCapture\n", infoPtr->hwndSelf);
01009             SetCapture(infoPtr->hwndSelf);
01010             infoPtr->bCapture = TRUE;
01011         }
01012         if (infoPtr->dwStyle & PGS_AUTOSCROLL)
01013         SetTimer(infoPtr->hwndSelf, TIMERID1, 0x3e, 0);
01014         hdc = GetWindowDC(infoPtr->hwndSelf);
01015         /* OffsetRect(wnrect, 0 | 1, 0 | 1) */
01016         PAGER_DrawButton(hdc, infoPtr->clrBk, *btnrect,
01017                  infoPtr->dwStyle & PGS_HORZ, topLeft, btnstate);
01018         ReleaseDC(infoPtr->hwndSelf, hdc);
01019         return 0;
01020     }
01021     }
01022 
01023     /* If we think we are captured, then do release */
01024     if (infoPtr->bCapture && (WindowFromPoint(pt) != infoPtr->hwndSelf))
01025     {
01026         NMHDR nmhdr;
01027 
01028         infoPtr->bCapture = FALSE;
01029 
01030         if (GetCapture() == infoPtr->hwndSelf)
01031         {
01032             ReleaseCapture();
01033 
01034             if (infoPtr->TLbtnState == PGF_GRAYED)
01035             {
01036                 infoPtr->TLbtnState = PGF_INVISIBLE;
01037                 SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
01038                              SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
01039                              SWP_NOZORDER | SWP_NOACTIVATE);
01040             }
01041             else if (infoPtr->TLbtnState == PGF_HOT)
01042             {
01043             infoPtr->TLbtnState = PGF_NORMAL;
01044             /* FIXME: just invalidate button rect */
01045                 RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
01046             }
01047 
01048             if (infoPtr->BRbtnState == PGF_GRAYED)
01049             {
01050                 infoPtr->BRbtnState = PGF_INVISIBLE;
01051                 SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
01052                              SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
01053                              SWP_NOZORDER | SWP_NOACTIVATE);
01054             }
01055             else if (infoPtr->BRbtnState == PGF_HOT)
01056             {
01057             infoPtr->BRbtnState = PGF_NORMAL;
01058             /* FIXME: just invalidate button rect */
01059                 RedrawWindow(infoPtr->hwndSelf, NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
01060             }
01061 
01062             /* Notify parent of released mouse capture */
01063             memset(&nmhdr, 0, sizeof(NMHDR));
01064             nmhdr.hwndFrom = infoPtr->hwndSelf;
01065             nmhdr.idFrom   = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
01066             nmhdr.code = NM_RELEASEDCAPTURE;
01067         SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
01068         }
01069         if (IsWindow(infoPtr->hwndSelf))
01070             KillTimer(infoPtr->hwndSelf, TIMERID1);
01071     }
01072     return 0;
01073 }
01074 
01075 static LRESULT
01076 PAGER_LButtonDown (PAGER_INFO* infoPtr, INT keys, INT x, INT y)
01077 {
01078     BOOL repaintBtns = FALSE;
01079     POINT pt;
01080     INT hit;
01081 
01082     pt.x = x;
01083     pt.y = y;
01084 
01085     TRACE("[%p] at (%d,%d)\n", infoPtr->hwndSelf, x, y);
01086 
01087     hit = PAGER_HitTest(infoPtr, &pt);
01088 
01089     /* put btn in DEPRESSED state */
01090     if (hit == PGB_TOPORLEFT)
01091     {
01092         repaintBtns = infoPtr->TLbtnState != PGF_DEPRESSED;
01093         infoPtr->TLbtnState = PGF_DEPRESSED;
01094         SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0);
01095     }
01096     else if (hit == PGB_BOTTOMORRIGHT)
01097     {
01098         repaintBtns = infoPtr->BRbtnState != PGF_DEPRESSED;
01099         infoPtr->BRbtnState = PGF_DEPRESSED;
01100         SetTimer(infoPtr->hwndSelf, TIMERID1, INITIAL_DELAY, 0);
01101     }
01102 
01103     if (repaintBtns)
01104         SendMessageW(infoPtr->hwndSelf, WM_NCPAINT, 0, 0);
01105 
01106     switch(hit)
01107     {
01108     case PGB_TOPORLEFT:
01109         if (infoPtr->dwStyle & PGS_HORZ)
01110         {
01111             TRACE("[%p] PGF_SCROLLLEFT\n", infoPtr->hwndSelf);
01112             PAGER_Scroll(infoPtr, PGF_SCROLLLEFT);
01113         }
01114         else
01115         {
01116             TRACE("[%p] PGF_SCROLLUP\n", infoPtr->hwndSelf);
01117             PAGER_Scroll(infoPtr, PGF_SCROLLUP);
01118         }
01119         break;
01120     case PGB_BOTTOMORRIGHT:
01121         if (infoPtr->dwStyle & PGS_HORZ)
01122         {
01123             TRACE("[%p] PGF_SCROLLRIGHT\n", infoPtr->hwndSelf);
01124             PAGER_Scroll(infoPtr, PGF_SCROLLRIGHT);
01125         }
01126         else
01127         {
01128             TRACE("[%p] PGF_SCROLLDOWN\n", infoPtr->hwndSelf);
01129             PAGER_Scroll(infoPtr, PGF_SCROLLDOWN);
01130         }
01131         break;
01132     default:
01133         break;
01134     }
01135 
01136     return 0;
01137 }
01138 
01139 static LRESULT
01140 PAGER_LButtonUp (PAGER_INFO* infoPtr, INT keys, INT x, INT y)
01141 {
01142     TRACE("[%p]\n", infoPtr->hwndSelf);
01143 
01144     KillTimer (infoPtr->hwndSelf, TIMERID1);
01145     KillTimer (infoPtr->hwndSelf, TIMERID2);
01146 
01147     /* make PRESSED btns NORMAL but don't hide gray btns */
01148     if (infoPtr->TLbtnState & (PGF_HOT | PGF_DEPRESSED))
01149         infoPtr->TLbtnState = PGF_NORMAL;
01150     if (infoPtr->BRbtnState & (PGF_HOT | PGF_DEPRESSED))
01151         infoPtr->BRbtnState = PGF_NORMAL;
01152 
01153     return 0;
01154 }
01155 
01156 static LRESULT
01157 PAGER_Timer (PAGER_INFO* infoPtr, INT nTimerId)
01158 {
01159     INT dir;
01160 
01161     /* if initial timer, kill it and start the repeat timer */
01162     if (nTimerId == TIMERID1) {
01163     if (infoPtr->TLbtnState == PGF_HOT)
01164         dir = (infoPtr->dwStyle & PGS_HORZ) ?
01165         PGF_SCROLLLEFT : PGF_SCROLLUP;
01166     else
01167         dir = (infoPtr->dwStyle & PGS_HORZ) ?
01168         PGF_SCROLLRIGHT : PGF_SCROLLDOWN;
01169     TRACE("[%p] TIMERID1: style=%08x, dir=%d\n",
01170               infoPtr->hwndSelf, infoPtr->dwStyle, dir);
01171     KillTimer(infoPtr->hwndSelf, TIMERID1);
01172     SetTimer(infoPtr->hwndSelf, TIMERID1, REPEAT_DELAY, 0);
01173     if (infoPtr->dwStyle & PGS_AUTOSCROLL) {
01174         PAGER_Scroll(infoPtr, dir);
01175         SetWindowPos(infoPtr->hwndSelf, 0, 0, 0, 0, 0,
01176              SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE |
01177              SWP_NOZORDER | SWP_NOACTIVATE);
01178     }
01179     return 0;
01180 
01181     }
01182 
01183     TRACE("[%p] TIMERID2: dir=%d\n", infoPtr->hwndSelf, infoPtr->direction);
01184     KillTimer(infoPtr->hwndSelf, TIMERID2);
01185     if (infoPtr->direction > 0) {
01186     PAGER_Scroll(infoPtr, infoPtr->direction);
01187     SetTimer(infoPtr->hwndSelf, TIMERID2, REPEAT_DELAY, 0);
01188     }
01189     return 0;
01190 }
01191 
01192 static LRESULT
01193 PAGER_EraseBackground (const PAGER_INFO* infoPtr, HDC hdc)
01194 {
01195     POINT pt, ptorig;
01196     HWND parent;
01197 
01198     pt.x = 0;
01199     pt.y = 0;
01200     parent = GetParent(infoPtr->hwndSelf);
01201     MapWindowPoints(infoPtr->hwndSelf, parent, &pt, 1);
01202     OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig);
01203     SendMessageW (parent, WM_ERASEBKGND, (WPARAM)hdc, 0);
01204     SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0);
01205 
01206     return 0;
01207 }
01208 
01209 
01210 static LRESULT
01211 PAGER_Size (PAGER_INFO* infoPtr, INT type, INT x, INT y)
01212 {
01213     /* note that WM_SIZE is sent whenever NCCalcSize resizes the client wnd */
01214 
01215     TRACE("[%p] %d,%d\n", infoPtr->hwndSelf, x, y);
01216 
01217     if (infoPtr->dwStyle & PGS_HORZ)
01218         infoPtr->nHeight = y;
01219     else
01220         infoPtr->nWidth = x;
01221 
01222     return PAGER_RecalcSize(infoPtr);
01223 }
01224 
01225 
01226 static LRESULT 
01227 PAGER_StyleChanged(PAGER_INFO *infoPtr, WPARAM wStyleType, const STYLESTRUCT *lpss)
01228 {
01229     DWORD oldStyle = infoPtr->dwStyle;
01230 
01231     TRACE("(styletype=%lx, styleOld=0x%08x, styleNew=0x%08x)\n",
01232           wStyleType, lpss->styleOld, lpss->styleNew);
01233 
01234     if (wStyleType != GWL_STYLE) return 0;
01235   
01236     infoPtr->dwStyle = lpss->styleNew;
01237 
01238     if ((oldStyle ^ lpss->styleNew) & (PGS_HORZ | PGS_VERT))
01239     {
01240         PAGER_RecalcSize(infoPtr);
01241     }
01242 
01243     return 0;
01244 }
01245 
01246 static LRESULT WINAPI
01247 PAGER_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
01248 {
01249     PAGER_INFO *infoPtr = (PAGER_INFO *)GetWindowLongPtrW(hwnd, 0);
01250 
01251     if (!infoPtr && (uMsg != WM_CREATE))
01252     return DefWindowProcW (hwnd, uMsg, wParam, lParam);
01253 
01254     switch (uMsg)
01255     {
01256         case EM_FMTLINES:
01257         return PAGER_FmtLines(infoPtr);
01258 
01259         case PGM_FORWARDMOUSE:
01260             return PAGER_ForwardMouse (infoPtr, (BOOL)wParam);
01261 
01262         case PGM_GETBKCOLOR:
01263             return PAGER_GetBkColor(infoPtr);
01264 
01265         case PGM_GETBORDER:
01266             return PAGER_GetBorder(infoPtr);
01267 
01268         case PGM_GETBUTTONSIZE:
01269             return PAGER_GetButtonSize(infoPtr);
01270 
01271         case PGM_GETPOS:
01272             return PAGER_GetPos(infoPtr);
01273 
01274         case PGM_GETBUTTONSTATE:
01275             return PAGER_GetButtonState (infoPtr, (INT)lParam);
01276 
01277 /*      case PGM_GETDROPTARGET: */
01278 
01279         case PGM_RECALCSIZE:
01280             return PAGER_RecalcSize(infoPtr);
01281 
01282         case PGM_SETBKCOLOR:
01283             return PAGER_SetBkColor (infoPtr, (COLORREF)lParam);
01284 
01285         case PGM_SETBORDER:
01286             return PAGER_SetBorder (infoPtr, (INT)lParam);
01287 
01288         case PGM_SETBUTTONSIZE:
01289             return PAGER_SetButtonSize (infoPtr, (INT)lParam);
01290 
01291         case PGM_SETCHILD:
01292             return PAGER_SetChild (infoPtr, (HWND)lParam);
01293 
01294         case PGM_SETPOS:
01295             return PAGER_SetPos(infoPtr, (INT)lParam, FALSE);
01296 
01297         case WM_CREATE:
01298             return PAGER_Create (hwnd, (LPCREATESTRUCTW)lParam);
01299 
01300         case WM_DESTROY:
01301             return PAGER_Destroy (infoPtr);
01302 
01303         case WM_SIZE:
01304             return PAGER_Size (infoPtr, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
01305 
01306         case WM_NCPAINT:
01307             return PAGER_NCPaint (infoPtr, (HRGN)wParam);
01308 
01309         case WM_WINDOWPOSCHANGING:
01310             return PAGER_WindowPosChanging (infoPtr, (WINDOWPOS*)lParam);
01311 
01312         case WM_STYLECHANGED:
01313             return PAGER_StyleChanged(infoPtr, wParam, (LPSTYLESTRUCT)lParam);
01314 
01315         case WM_NCCALCSIZE:
01316             return PAGER_NCCalcSize (infoPtr, wParam, (LPRECT)lParam);
01317 
01318         case WM_NCHITTEST:
01319             return PAGER_NCHitTest (infoPtr, (short)LOWORD(lParam), (short)HIWORD(lParam));
01320 
01321         case WM_MOUSEMOVE:
01322             if (infoPtr->bForward && infoPtr->hwndChild)
01323                 PostMessageW(infoPtr->hwndChild, WM_MOUSEMOVE, wParam, lParam);
01324             return PAGER_MouseMove (infoPtr, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
01325 
01326         case WM_LBUTTONDOWN:
01327             return PAGER_LButtonDown (infoPtr, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
01328 
01329         case WM_LBUTTONUP:
01330             return PAGER_LButtonUp (infoPtr, (INT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
01331 
01332         case WM_ERASEBKGND:
01333             return PAGER_EraseBackground (infoPtr, (HDC)wParam);
01334 
01335         case WM_TIMER:
01336             return PAGER_Timer (infoPtr, (INT)wParam);
01337 
01338         case WM_NOTIFY:
01339         case WM_COMMAND:
01340             return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam);
01341 
01342         default:
01343             return DefWindowProcW (hwnd, uMsg, wParam, lParam);
01344     }
01345 }
01346 
01347 
01348 VOID
01349 PAGER_Register (void)
01350 {
01351     WNDCLASSW wndClass;
01352 
01353     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
01354     wndClass.style         = CS_GLOBALCLASS;
01355     wndClass.lpfnWndProc   = PAGER_WindowProc;
01356     wndClass.cbClsExtra    = 0;
01357     wndClass.cbWndExtra    = sizeof(PAGER_INFO *);
01358     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
01359     wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);
01360     wndClass.lpszClassName = WC_PAGESCROLLERW;
01361 
01362     RegisterClassW (&wndClass);
01363 }
01364 
01365 
01366 VOID
01367 PAGER_Unregister (void)
01368 {
01369     UnregisterClassW (WC_PAGESCROLLERW, NULL);
01370 }

Generated on Sun May 27 2012 04:23:02 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.