Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpager.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
1.7.6.1
|