Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenrebar.c
Go to the documentation of this file.
00001 /* 00002 * Rebar control 00003 * 00004 * Copyright 1998, 1999 Eric Kohl 00005 * Copyright 2007, 2008 Mikolaj Zalewski 00006 * 00007 * This library is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with this library; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00020 * 00021 * NOTES 00022 * 00023 * This code was audited for completeness against the documented features 00024 * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman. 00025 * 00026 * Unless otherwise noted, we believe this code to be complete, as per 00027 * the specification mentioned above. 00028 * If you discover missing features or bugs please note them below. 00029 * 00030 * TODO 00031 * Styles: 00032 * - RBS_DBLCLKTOGGLE 00033 * - RBS_FIXEDORDER 00034 * - RBS_REGISTERDROP 00035 * - RBS_TOOLTIPS 00036 * Messages: 00037 * - RB_BEGINDRAG 00038 * - RB_DRAGMOVE 00039 * - RB_ENDDRAG 00040 * - RB_GETBANDMARGINS 00041 * - RB_GETCOLORSCHEME 00042 * - RB_GETDROPTARGET 00043 * - RB_GETPALETTE 00044 * - RB_SETCOLORSCHEME 00045 * - RB_SETPALETTE 00046 * - RB_SETTOOLTIPS 00047 * - WM_CHARTOITEM 00048 * - WM_LBUTTONDBLCLK 00049 * - WM_MEASUREITEM 00050 * - WM_PALETTECHANGED 00051 * - WM_QUERYNEWPALETTE 00052 * - WM_RBUTTONDOWN 00053 * - WM_RBUTTONUP 00054 * - WM_VKEYTOITEM 00055 * - WM_WININICHANGE 00056 * Notifications: 00057 * - NM_HCHITTEST 00058 * - NM_RELEASEDCAPTURE 00059 * - RBN_AUTOBREAK 00060 * - RBN_GETOBJECT 00061 * - RBN_MINMAX 00062 * Band styles: 00063 * - RBBS_FIXEDBMP 00064 * Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT) 00065 * to set the size of the separator width (the value SEP_WIDTH_SIZE 00066 * in here). Should be fixed!! 00067 */ 00068 00069 /* 00070 * Testing: set to 1 to make background brush *always* green 00071 */ 00072 #define GLATESTING 0 00073 00074 /* 00075 * 3. REBAR_MoveChildWindows should have a loop because more than 00076 * one pass (together with the RBN_CHILDSIZEs) is made on 00077 * at least RB_INSERTBAND 00078 */ 00079 00080 #include <assert.h> 00081 #include <stdarg.h> 00082 #include <stdlib.h> 00083 #include <string.h> 00084 00085 #include "windef.h" 00086 #include "winbase.h" 00087 #include "wingdi.h" 00088 #include "wine/unicode.h" 00089 #include "winuser.h" 00090 #include "winnls.h" 00091 #include "commctrl.h" 00092 #include "comctl32.h" 00093 #include "uxtheme.h" 00094 #include "vssym32.h" 00095 #include "wine/debug.h" 00096 00097 WINE_DEFAULT_DEBUG_CHANNEL(rebar); 00098 00099 typedef struct 00100 { 00101 UINT fStyle; 00102 UINT fMask; 00103 COLORREF clrFore; 00104 COLORREF clrBack; 00105 INT iImage; 00106 HWND hwndChild; 00107 UINT cxMinChild; /* valid if _CHILDSIZE */ 00108 UINT cyMinChild; /* valid if _CHILDSIZE */ 00109 UINT cx; /* valid if _SIZE */ 00110 HBITMAP hbmBack; 00111 UINT wID; 00112 UINT cyChild; /* valid if _CHILDSIZE */ 00113 UINT cyMaxChild; /* valid if _CHILDSIZE */ 00114 UINT cyIntegral; /* valid if _CHILDSIZE */ 00115 UINT cxIdeal; 00116 LPARAM lParam; 00117 UINT cxHeader; 00118 00119 INT cxEffective; /* current cx for band */ 00120 UINT cyHeader; /* the height of the header */ 00121 UINT cxMinBand; /* minimum cx for band */ 00122 UINT cyMinBand; /* minimum cy for band */ 00123 00124 UINT cyRowSoFar; /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */ 00125 INT iRow; /* zero-based index of the row this band assigned to */ 00126 UINT fStatus; /* status flags, reset only by _Validate */ 00127 UINT fDraw; /* drawing flags, reset only by _Layout */ 00128 UINT uCDret; /* last return from NM_CUSTOMDRAW */ 00129 RECT rcBand; /* calculated band rectangle - coordinates swapped for CCS_VERT */ 00130 RECT rcGripper; /* calculated gripper rectangle */ 00131 RECT rcCapImage; /* calculated caption image rectangle */ 00132 RECT rcCapText; /* calculated caption text rectangle */ 00133 RECT rcChild; /* calculated child rectangle */ 00134 RECT rcChevron; /* calculated chevron rectangle */ 00135 00136 LPWSTR lpText; 00137 HWND hwndPrevParent; 00138 } REBAR_BAND; 00139 00140 /* fStatus flags */ 00141 #define HAS_GRIPPER 0x00000001 00142 #define HAS_IMAGE 0x00000002 00143 #define HAS_TEXT 0x00000004 00144 00145 /* fDraw flags */ 00146 #define DRAW_GRIPPER 0x00000001 00147 #define DRAW_IMAGE 0x00000002 00148 #define DRAW_TEXT 0x00000004 00149 #define DRAW_CHEVRONHOT 0x00000040 00150 #define DRAW_CHEVRONPUSHED 0x00000080 00151 #define NTF_INVALIDATE 0x01000000 00152 00153 typedef struct 00154 { 00155 COLORREF clrBk; /* background color */ 00156 COLORREF clrText; /* text color */ 00157 COLORREF clrBtnText; /* system color for BTNTEXT */ 00158 COLORREF clrBtnFace; /* system color for BTNFACE */ 00159 HIMAGELIST himl; /* handle to imagelist */ 00160 UINT uNumBands; /* # of bands in rebar (first=0, last=uNumBands-1 */ 00161 UINT uNumRows; /* # of rows of bands (first=1, last=uNumRows */ 00162 HWND hwndSelf; /* handle of REBAR window itself */ 00163 HWND hwndToolTip; /* handle to the tool tip control */ 00164 HWND hwndNotify; /* notification window (parent) */ 00165 HFONT hDefaultFont; 00166 HFONT hFont; /* handle to the rebar's font */ 00167 SIZE imageSize; /* image size (image list) */ 00168 DWORD dwStyle; /* window style */ 00169 DWORD orgStyle; /* original style (dwStyle may change) */ 00170 SIZE calcSize; /* calculated rebar size - coordinates swapped for CCS_VERT */ 00171 BOOL bUnicode; /* TRUE if parent wants notify in W format */ 00172 BOOL DoRedraw; /* TRUE to actually draw bands */ 00173 UINT fStatus; /* Status flags (see below) */ 00174 HCURSOR hcurArrow; /* handle to the arrow cursor */ 00175 HCURSOR hcurHorz; /* handle to the EW cursor */ 00176 HCURSOR hcurVert; /* handle to the NS cursor */ 00177 HCURSOR hcurDrag; /* handle to the drag cursor */ 00178 INT iVersion; /* version number */ 00179 POINT dragStart; /* x,y of button down */ 00180 POINT dragNow; /* x,y of this MouseMove */ 00181 INT iOldBand; /* last band that had the mouse cursor over it */ 00182 INT ihitoffset; /* offset of hotspot from gripper.left */ 00183 INT ichevronhotBand; /* last band that had a hot chevron */ 00184 INT iGrabbedBand;/* band number of band whose gripper was grabbed */ 00185 00186 HDPA bands; /* pointer to the array of rebar bands */ 00187 } REBAR_INFO; 00188 00189 /* fStatus flags */ 00190 #define BEGIN_DRAG_ISSUED 0x00000001 00191 #define SELF_RESIZE 0x00000002 00192 #define BAND_NEEDS_REDRAW 0x00000020 00193 00194 /* used by Windows to mark that the header size has been set by the user and shouldn't be changed */ 00195 #define RBBS_UNDOC_FIXEDHEADER 0x40000000 00196 00197 /* ---- REBAR layout constants. Mostly determined by ---- */ 00198 /* ---- experiment on WIN 98. ---- */ 00199 00200 /* Width (or height) of separators between bands (either horz. or */ 00201 /* vert.). True only if RBS_BANDBORDERS is set */ 00202 #define SEP_WIDTH_SIZE 2 00203 #define SEP_WIDTH ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0) 00204 00205 /* Blank (background color) space between Gripper (if present) */ 00206 /* and next item (image, text, or window). Always present */ 00207 #define REBAR_ALWAYS_SPACE 4 00208 00209 /* Blank (background color) space after Image (if present). */ 00210 #define REBAR_POST_IMAGE 2 00211 00212 /* Blank (background color) space after Text (if present). */ 00213 #define REBAR_POST_TEXT 4 00214 00215 /* Height of vertical gripper in a CCS_VERT rebar. */ 00216 #define GRIPPER_HEIGHT 16 00217 00218 /* Blank (background color) space before Gripper (if present). */ 00219 #define REBAR_PRE_GRIPPER 2 00220 00221 /* Width (of normal vertical gripper) or height (of horz. gripper) */ 00222 /* if present. */ 00223 #define GRIPPER_WIDTH 3 00224 00225 /* Width of the chevron button if present */ 00226 #define CHEVRON_WIDTH 10 00227 00228 /* the gap between the child and the next band */ 00229 #define REBAR_POST_CHILD 4 00230 00231 /* Height of divider for Rebar if not disabled (CCS_NODIVIDER) */ 00232 /* either top or bottom */ 00233 #define REBAR_DIVIDER 2 00234 00235 /* height of a rebar without a child */ 00236 #define REBAR_NO_CHILD_HEIGHT 4 00237 00238 /* minimum vertical height of a normal bar */ 00239 /* or minimum width of a CCS_VERT bar - from experiment on Win2k */ 00240 #define REBAR_MINSIZE 23 00241 00242 /* This is the increment that is used over the band height */ 00243 #define REBARSPACE(a) ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0) 00244 00245 /* ---- End of REBAR layout constants. ---- */ 00246 00247 #define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */ 00248 00249 /* The following define determines if a given band is hidden */ 00250 #define HIDDENBAND(a) (((a)->fStyle & RBBS_HIDDEN) || \ 00251 ((infoPtr->dwStyle & CCS_VERT) && \ 00252 ((a)->fStyle & RBBS_NOVERT))) 00253 00254 #define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0)) 00255 00256 static LRESULT REBAR_NotifyFormat(REBAR_INFO *infoPtr, LPARAM lParam); 00257 static void REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout); 00258 00259 /* no index check here */ 00260 static inline REBAR_BAND* REBAR_GetBand(const REBAR_INFO *infoPtr, INT i) 00261 { 00262 assert(i >= 0 && i < infoPtr->uNumBands); 00263 return DPA_GetPtr(infoPtr->bands, i); 00264 } 00265 00266 /* "constant values" retrieved when DLL was initialized */ 00267 /* FIXME we do this when the classes are registered. */ 00268 static UINT mindragx = 0; 00269 static UINT mindragy = 0; 00270 00271 static const char * const band_stylename[] = { 00272 "RBBS_BREAK", /* 0001 */ 00273 "RBBS_FIXEDSIZE", /* 0002 */ 00274 "RBBS_CHILDEDGE", /* 0004 */ 00275 "RBBS_HIDDEN", /* 0008 */ 00276 "RBBS_NOVERT", /* 0010 */ 00277 "RBBS_FIXEDBMP", /* 0020 */ 00278 "RBBS_VARIABLEHEIGHT", /* 0040 */ 00279 "RBBS_GRIPPERALWAYS", /* 0080 */ 00280 "RBBS_NOGRIPPER", /* 0100 */ 00281 NULL }; 00282 00283 static const char * const band_maskname[] = { 00284 "RBBIM_STYLE", /* 0x00000001 */ 00285 "RBBIM_COLORS", /* 0x00000002 */ 00286 "RBBIM_TEXT", /* 0x00000004 */ 00287 "RBBIM_IMAGE", /* 0x00000008 */ 00288 "RBBIM_CHILD", /* 0x00000010 */ 00289 "RBBIM_CHILDSIZE", /* 0x00000020 */ 00290 "RBBIM_SIZE", /* 0x00000040 */ 00291 "RBBIM_BACKGROUND", /* 0x00000080 */ 00292 "RBBIM_ID", /* 0x00000100 */ 00293 "RBBIM_IDEALSIZE", /* 0x00000200 */ 00294 "RBBIM_LPARAM", /* 0x00000400 */ 00295 "RBBIM_HEADERSIZE", /* 0x00000800 */ 00296 NULL }; 00297 00298 00299 static CHAR line[200]; 00300 00301 static const WCHAR themeClass[] = { 'R','e','b','a','r',0 }; 00302 00303 static CHAR * 00304 REBAR_FmtStyle( UINT style) 00305 { 00306 INT i = 0; 00307 00308 *line = 0; 00309 while (band_stylename[i]) { 00310 if (style & (1<<i)) { 00311 if (*line != 0) strcat(line, " | "); 00312 strcat(line, band_stylename[i]); 00313 } 00314 i++; 00315 } 00316 return line; 00317 } 00318 00319 00320 static CHAR * 00321 REBAR_FmtMask( UINT mask) 00322 { 00323 INT i = 0; 00324 00325 *line = 0; 00326 while (band_maskname[i]) { 00327 if (mask & (1<<i)) { 00328 if (*line != 0) strcat(line, " | "); 00329 strcat(line, band_maskname[i]); 00330 } 00331 i++; 00332 } 00333 return line; 00334 } 00335 00336 00337 static VOID 00338 REBAR_DumpBandInfo(const REBARBANDINFOW *pB) 00339 { 00340 if( !TRACE_ON(rebar) ) return; 00341 TRACE("band info: "); 00342 if (pB->fMask & RBBIM_ID) 00343 TRACE("ID=%u, ", pB->wID); 00344 TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild); 00345 if (pB->fMask & RBBIM_COLORS) 00346 TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack); 00347 TRACE("\n"); 00348 00349 TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(pB->fMask)); 00350 if (pB->fMask & RBBIM_STYLE) 00351 TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(pB->fStyle)); 00352 if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) { 00353 TRACE("band info:"); 00354 if (pB->fMask & RBBIM_SIZE) 00355 TRACE(" cx=%u", pB->cx); 00356 if (pB->fMask & RBBIM_IDEALSIZE) 00357 TRACE(" xIdeal=%u", pB->cxIdeal); 00358 if (pB->fMask & RBBIM_HEADERSIZE) 00359 TRACE(" xHeader=%u", pB->cxHeader); 00360 if (pB->fMask & RBBIM_LPARAM) 00361 TRACE(" lParam=0x%08lx", pB->lParam); 00362 TRACE("\n"); 00363 } 00364 if (pB->fMask & RBBIM_CHILDSIZE) 00365 TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", 00366 pB->cxMinChild, 00367 pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); 00368 } 00369 00370 static VOID 00371 REBAR_DumpBand (const REBAR_INFO *iP) 00372 { 00373 REBAR_BAND *pB; 00374 UINT i; 00375 00376 if(! TRACE_ON(rebar) ) return; 00377 00378 TRACE("hwnd=%p: color=%08x/%08x, bands=%u, rows=%u, cSize=%d,%d\n", 00379 iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows, 00380 iP->calcSize.cx, iP->calcSize.cy); 00381 TRACE("hwnd=%p: flags=%08x, dragStart=%d,%d, dragNow=%d,%d, iGrabbedBand=%d\n", 00382 iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y, 00383 iP->dragNow.x, iP->dragNow.y, 00384 iP->iGrabbedBand); 00385 TRACE("hwnd=%p: style=%08x, notify in Unicode=%s, redraw=%s\n", 00386 iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE", 00387 (iP->DoRedraw)?"TRUE":"FALSE"); 00388 for (i = 0; i < iP->uNumBands; i++) { 00389 pB = REBAR_GetBand(iP, i); 00390 TRACE("band # %u:", i); 00391 if (pB->fMask & RBBIM_ID) 00392 TRACE(" ID=%u", pB->wID); 00393 if (pB->fMask & RBBIM_CHILD) 00394 TRACE(" child=%p", pB->hwndChild); 00395 if (pB->fMask & RBBIM_COLORS) 00396 TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack); 00397 TRACE("\n"); 00398 TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(pB->fMask)); 00399 if (pB->fMask & RBBIM_STYLE) 00400 TRACE("band # %u: style=0x%08x (%s)\n", 00401 i, pB->fStyle, REBAR_FmtStyle(pB->fStyle)); 00402 TRACE("band # %u: xHeader=%u", 00403 i, pB->cxHeader); 00404 if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) { 00405 if (pB->fMask & RBBIM_SIZE) 00406 TRACE(" cx=%u", pB->cx); 00407 if (pB->fMask & RBBIM_IDEALSIZE) 00408 TRACE(" xIdeal=%u", pB->cxIdeal); 00409 if (pB->fMask & RBBIM_LPARAM) 00410 TRACE(" lParam=0x%08lx", pB->lParam); 00411 } 00412 TRACE("\n"); 00413 if (RBBIM_CHILDSIZE) 00414 TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", 00415 i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); 00416 if (pB->fMask & RBBIM_TEXT) 00417 TRACE("band # %u: text=%s\n", 00418 i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)"); 00419 TRACE("band # %u: cxMinBand=%u, cxEffective=%u, cyMinBand=%u\n", 00420 i, pB->cxMinBand, pB->cxEffective, pB->cyMinBand); 00421 TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%s), Grip=(%s)\n", 00422 i, pB->fStatus, pB->fDraw, wine_dbgstr_rect(&pB->rcBand), 00423 wine_dbgstr_rect(&pB->rcGripper)); 00424 TRACE("band # %u: Img=(%s), Txt=(%s), Child=(%s)\n", 00425 i, wine_dbgstr_rect(&pB->rcCapImage), 00426 wine_dbgstr_rect(&pB->rcCapText), wine_dbgstr_rect(&pB->rcChild)); 00427 } 00428 00429 } 00430 00431 /* dest can be equal to src */ 00432 static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src) 00433 { 00434 if (infoPtr->dwStyle & CCS_VERT) { 00435 int tmp; 00436 tmp = src->left; 00437 dest->left = src->top; 00438 dest->top = tmp; 00439 00440 tmp = src->right; 00441 dest->right = src->bottom; 00442 dest->bottom = tmp; 00443 } else { 00444 *dest = *src; 00445 } 00446 } 00447 00448 static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect) 00449 { 00450 if (infoPtr->dwStyle & CCS_VERT) 00451 return lpRect->bottom - lpRect->top; 00452 return lpRect->right - lpRect->left; 00453 } 00454 00455 static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect) 00456 { 00457 if (infoPtr->dwStyle & CCS_VERT) 00458 return lpRect->right - lpRect->left; 00459 return lpRect->bottom - lpRect->top; 00460 } 00461 00462 static int round_child_height(const REBAR_BAND *lpBand, int cyHeight) 00463 { 00464 int cy = 0; 00465 if (lpBand->cyIntegral == 0) 00466 return cyHeight; 00467 cy = max(cyHeight - (int)lpBand->cyMinChild, 0); 00468 cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral; 00469 cy = min(cy, lpBand->cyMaxChild); 00470 return cy; 00471 } 00472 00473 static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 00474 { 00475 lpBand->cyMinBand = max(lpBand->cyHeader, 00476 (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT)); 00477 } 00478 00479 static void 00480 REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef) 00481 { 00482 INT x, y; 00483 HPEN hPen, hOldPen; 00484 00485 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; 00486 hOldPen = SelectObject ( hdc, hPen ); 00487 x = left + 2; 00488 y = top; 00489 MoveToEx (hdc, x, y, NULL); 00490 LineTo (hdc, x+5, y++); x++; 00491 MoveToEx (hdc, x, y, NULL); 00492 LineTo (hdc, x+3, y++); x++; 00493 MoveToEx (hdc, x, y, NULL); 00494 LineTo (hdc, x+1, y); 00495 SelectObject( hdc, hOldPen ); 00496 DeleteObject( hPen ); 00497 } 00498 00499 static HWND 00500 REBAR_GetNotifyParent (const REBAR_INFO *infoPtr) 00501 { 00502 HWND parent, owner; 00503 00504 parent = infoPtr->hwndNotify; 00505 if (!parent) { 00506 parent = GetParent (infoPtr->hwndSelf); 00507 owner = GetWindow (infoPtr->hwndSelf, GW_OWNER); 00508 if (owner) parent = owner; 00509 } 00510 return parent; 00511 } 00512 00513 00514 static INT 00515 REBAR_Notify (NMHDR *nmhdr, const REBAR_INFO *infoPtr, UINT code) 00516 { 00517 HWND parent; 00518 00519 parent = REBAR_GetNotifyParent (infoPtr); 00520 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); 00521 nmhdr->hwndFrom = infoPtr->hwndSelf; 00522 nmhdr->code = code; 00523 00524 TRACE("window %p, code=%08x, via %s\n", parent, code, (infoPtr->bUnicode)?"Unicode":"ANSI"); 00525 00526 return SendMessageW(parent, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr); 00527 } 00528 00529 static INT 00530 REBAR_Notify_NMREBAR (const REBAR_INFO *infoPtr, UINT uBand, UINT code) 00531 { 00532 NMREBAR notify_rebar; 00533 00534 notify_rebar.dwMask = 0; 00535 if (uBand != -1) { 00536 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand); 00537 00538 if (lpBand->fMask & RBBIM_ID) { 00539 notify_rebar.dwMask |= RBNM_ID; 00540 notify_rebar.wID = lpBand->wID; 00541 } 00542 if (lpBand->fMask & RBBIM_LPARAM) { 00543 notify_rebar.dwMask |= RBNM_LPARAM; 00544 notify_rebar.lParam = lpBand->lParam; 00545 } 00546 if (lpBand->fMask & RBBIM_STYLE) { 00547 notify_rebar.dwMask |= RBNM_STYLE; 00548 notify_rebar.fStyle = lpBand->fStyle; 00549 } 00550 } 00551 notify_rebar.uBand = uBand; 00552 return REBAR_Notify ((NMHDR *)¬ify_rebar, infoPtr, code); 00553 } 00554 00555 static VOID 00556 REBAR_DrawBand (HDC hdc, const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 00557 { 00558 HFONT hOldFont = 0; 00559 INT oldBkMode = 0; 00560 NMCUSTOMDRAW nmcd; 00561 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 00562 RECT rcBand; 00563 00564 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 00565 00566 if (lpBand->fDraw & DRAW_TEXT) { 00567 hOldFont = SelectObject (hdc, infoPtr->hFont); 00568 oldBkMode = SetBkMode (hdc, TRANSPARENT); 00569 } 00570 00571 /* should test for CDRF_NOTIFYITEMDRAW here */ 00572 nmcd.dwDrawStage = CDDS_ITEMPREPAINT; 00573 nmcd.hdc = hdc; 00574 nmcd.rc = rcBand; 00575 nmcd.rc.right = lpBand->rcCapText.right; 00576 nmcd.rc.bottom = lpBand->rcCapText.bottom; 00577 nmcd.dwItemSpec = lpBand->wID; 00578 nmcd.uItemState = 0; 00579 nmcd.lItemlParam = lpBand->lParam; 00580 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); 00581 if (lpBand->uCDret == CDRF_SKIPDEFAULT) { 00582 if (oldBkMode != TRANSPARENT) 00583 SetBkMode (hdc, oldBkMode); 00584 SelectObject (hdc, hOldFont); 00585 return; 00586 } 00587 00588 /* draw gripper */ 00589 if (lpBand->fDraw & DRAW_GRIPPER) 00590 { 00591 if (theme) 00592 { 00593 RECT rcGripper = lpBand->rcGripper; 00594 int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER; 00595 GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper); 00596 OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left, 00597 lpBand->rcGripper.top - rcGripper.top); 00598 DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL); 00599 } 00600 else 00601 DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); 00602 } 00603 00604 /* draw caption image */ 00605 if (lpBand->fDraw & DRAW_IMAGE) { 00606 POINT pt; 00607 00608 /* center image */ 00609 pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2; 00610 pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2; 00611 00612 ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc, 00613 pt.x, pt.y, 00614 ILD_TRANSPARENT); 00615 } 00616 00617 /* draw caption text */ 00618 if (lpBand->fDraw & DRAW_TEXT) { 00619 /* need to handle CDRF_NEWFONT here */ 00620 INT oldBkMode = SetBkMode (hdc, TRANSPARENT); 00621 COLORREF oldcolor = CLR_NONE; 00622 COLORREF new; 00623 if (lpBand->clrFore != CLR_NONE) { 00624 new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText : 00625 lpBand->clrFore; 00626 oldcolor = SetTextColor (hdc, new); 00627 } 00628 DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, 00629 DT_CENTER | DT_VCENTER | DT_SINGLELINE); 00630 if (oldBkMode != TRANSPARENT) 00631 SetBkMode (hdc, oldBkMode); 00632 if (lpBand->clrFore != CLR_NONE) 00633 SetTextColor (hdc, oldcolor); 00634 SelectObject (hdc, hOldFont); 00635 } 00636 00637 if (!IsRectEmpty(&lpBand->rcChevron)) 00638 { 00639 if (theme) 00640 { 00641 int stateId; 00642 if (lpBand->fDraw & DRAW_CHEVRONPUSHED) 00643 stateId = CHEVS_PRESSED; 00644 else if (lpBand->fDraw & DRAW_CHEVRONHOT) 00645 stateId = CHEVS_HOT; 00646 else 00647 stateId = CHEVS_NORMAL; 00648 DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL); 00649 } 00650 else 00651 { 00652 if (lpBand->fDraw & DRAW_CHEVRONPUSHED) 00653 { 00654 DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 00655 REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME); 00656 } 00657 else if (lpBand->fDraw & DRAW_CHEVRONHOT) 00658 { 00659 DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); 00660 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); 00661 } 00662 else 00663 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); 00664 } 00665 } 00666 00667 if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) { 00668 nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; 00669 nmcd.hdc = hdc; 00670 nmcd.rc = rcBand; 00671 nmcd.rc.right = lpBand->rcCapText.right; 00672 nmcd.rc.bottom = lpBand->rcCapText.bottom; 00673 nmcd.dwItemSpec = lpBand->wID; 00674 nmcd.uItemState = 0; 00675 nmcd.lItemlParam = lpBand->lParam; 00676 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); 00677 } 00678 } 00679 00680 00681 static VOID 00682 REBAR_Refresh (const REBAR_INFO *infoPtr, HDC hdc) 00683 { 00684 REBAR_BAND *lpBand; 00685 UINT i; 00686 00687 if (!infoPtr->DoRedraw) return; 00688 00689 for (i = 0; i < infoPtr->uNumBands; i++) { 00690 lpBand = REBAR_GetBand(infoPtr, i); 00691 00692 if (HIDDENBAND(lpBand)) continue; 00693 00694 /* now draw the band */ 00695 TRACE("[%p] drawing band %i, flags=%08x\n", 00696 infoPtr->hwndSelf, i, lpBand->fDraw); 00697 REBAR_DrawBand (hdc, infoPtr, lpBand); 00698 } 00699 } 00700 00701 00702 static void 00703 REBAR_CalcHorzBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend) 00704 /* Function: this routine initializes all the rectangles in */ 00705 /* each band in a row to fit in the adjusted rcBand rect. */ 00706 /* *** Supports only Horizontal bars. *** */ 00707 { 00708 REBAR_BAND *lpBand; 00709 UINT i, xoff; 00710 RECT work; 00711 00712 for(i=rstart; i<rend; i++){ 00713 lpBand = REBAR_GetBand(infoPtr, i); 00714 if (HIDDENBAND(lpBand)) { 00715 SetRect (&lpBand->rcChild, 00716 lpBand->rcBand.right, lpBand->rcBand.top, 00717 lpBand->rcBand.right, lpBand->rcBand.bottom); 00718 continue; 00719 } 00720 00721 /* set initial gripper rectangle */ 00722 SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, 00723 lpBand->rcBand.left, lpBand->rcBand.bottom); 00724 00725 /* calculate gripper rectangle */ 00726 if ( lpBand->fStatus & HAS_GRIPPER) { 00727 lpBand->fDraw |= DRAW_GRIPPER; 00728 lpBand->rcGripper.left += REBAR_PRE_GRIPPER; 00729 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; 00730 lpBand->rcGripper.top += 2; 00731 lpBand->rcGripper.bottom -= 2; 00732 00733 SetRect (&lpBand->rcCapImage, 00734 lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top, 00735 lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom); 00736 } 00737 else { /* no gripper will be drawn */ 00738 xoff = 0; 00739 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) 00740 /* if no gripper but either image or text, then leave space */ 00741 xoff = REBAR_ALWAYS_SPACE; 00742 SetRect (&lpBand->rcCapImage, 00743 lpBand->rcBand.left+xoff, lpBand->rcBand.top, 00744 lpBand->rcBand.left+xoff, lpBand->rcBand.bottom); 00745 } 00746 00747 /* image is visible */ 00748 if (lpBand->fStatus & HAS_IMAGE) { 00749 lpBand->fDraw |= DRAW_IMAGE; 00750 lpBand->rcCapImage.right += infoPtr->imageSize.cx; 00751 lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy; 00752 00753 /* set initial caption text rectangle */ 00754 SetRect (&lpBand->rcCapText, 00755 lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1, 00756 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); 00757 } 00758 else { 00759 /* set initial caption text rectangle */ 00760 SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1, 00761 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); 00762 } 00763 00764 /* text is visible */ 00765 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { 00766 lpBand->fDraw |= DRAW_TEXT; 00767 lpBand->rcCapText.right = max(lpBand->rcCapText.left, 00768 lpBand->rcCapText.right-REBAR_POST_TEXT); 00769 } 00770 00771 /* set initial child window rectangle if there is a child */ 00772 if (lpBand->hwndChild) { 00773 00774 lpBand->rcChild.left = lpBand->rcBand.left + lpBand->cxHeader; 00775 lpBand->rcChild.right = lpBand->rcBand.right - REBAR_POST_CHILD; 00776 00777 if (lpBand->cyChild > 0) { 00778 00779 UINT yoff = (lpBand->rcBand.bottom - lpBand->rcBand.top - lpBand->cyChild) / 2; 00780 00781 /* center child if height is known */ 00782 lpBand->rcChild.top = lpBand->rcBand.top + yoff; 00783 lpBand->rcChild.bottom = lpBand->rcBand.top + yoff + lpBand->cyChild; 00784 } 00785 else { 00786 lpBand->rcChild.top = lpBand->rcBand.top; 00787 lpBand->rcChild.bottom = lpBand->rcBand.bottom; 00788 } 00789 00790 if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal)) 00791 { 00792 lpBand->rcChild.right -= CHEVRON_WIDTH; 00793 SetRect(&lpBand->rcChevron, lpBand->rcChild.right, 00794 lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH, 00795 lpBand->rcChild.bottom); 00796 } 00797 } 00798 else { 00799 SetRect (&lpBand->rcChild, 00800 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top, 00801 lpBand->rcBand.right, lpBand->rcBand.bottom); 00802 } 00803 00804 /* flag if notify required and invalidate rectangle */ 00805 if (lpBand->fDraw & NTF_INVALIDATE) { 00806 TRACE("invalidating (%d,%d)-(%d,%d)\n", 00807 lpBand->rcBand.left, 00808 lpBand->rcBand.top, 00809 lpBand->rcBand.right + SEP_WIDTH, 00810 lpBand->rcBand.bottom + SEP_WIDTH); 00811 lpBand->fDraw &= ~NTF_INVALIDATE; 00812 work = lpBand->rcBand; 00813 work.right += SEP_WIDTH; 00814 work.bottom += SEP_WIDTH; 00815 InvalidateRect(infoPtr->hwndSelf, &work, TRUE); 00816 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE); 00817 } 00818 00819 } 00820 00821 } 00822 00823 00824 static VOID 00825 REBAR_CalcVertBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend) 00826 /* Function: this routine initializes all the rectangles in */ 00827 /* each band in a row to fit in the adjusted rcBand rect. */ 00828 /* *** Supports only Vertical bars. *** */ 00829 { 00830 REBAR_BAND *lpBand; 00831 UINT i, xoff; 00832 RECT work; 00833 00834 for(i=rstart; i<rend; i++){ 00835 RECT rcBand; 00836 lpBand = REBAR_GetBand(infoPtr, i); 00837 if (HIDDENBAND(lpBand)) continue; 00838 00839 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 00840 00841 /* set initial gripper rectangle */ 00842 SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top); 00843 00844 /* calculate gripper rectangle */ 00845 if (lpBand->fStatus & HAS_GRIPPER) { 00846 lpBand->fDraw |= DRAW_GRIPPER; 00847 00848 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) { 00849 /* vertical gripper */ 00850 lpBand->rcGripper.left += 3; 00851 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; 00852 lpBand->rcGripper.top += REBAR_PRE_GRIPPER; 00853 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT; 00854 00855 /* initialize Caption image rectangle */ 00856 SetRect (&lpBand->rcCapImage, rcBand.left, 00857 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, 00858 rcBand.right, 00859 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); 00860 } 00861 else { 00862 /* horizontal gripper */ 00863 lpBand->rcGripper.left += 2; 00864 lpBand->rcGripper.right -= 2; 00865 lpBand->rcGripper.top += REBAR_PRE_GRIPPER; 00866 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_WIDTH; 00867 00868 /* initialize Caption image rectangle */ 00869 SetRect (&lpBand->rcCapImage, rcBand.left, 00870 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, 00871 rcBand.right, 00872 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); 00873 } 00874 } 00875 else { /* no gripper will be drawn */ 00876 xoff = 0; 00877 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) 00878 /* if no gripper but either image or text, then leave space */ 00879 xoff = REBAR_ALWAYS_SPACE; 00880 /* initialize Caption image rectangle */ 00881 SetRect (&lpBand->rcCapImage, 00882 rcBand.left, rcBand.top+xoff, 00883 rcBand.right, rcBand.top+xoff); 00884 } 00885 00886 /* image is visible */ 00887 if (lpBand->fStatus & HAS_IMAGE) { 00888 lpBand->fDraw |= DRAW_IMAGE; 00889 00890 lpBand->rcCapImage.right = lpBand->rcCapImage.left + infoPtr->imageSize.cx; 00891 lpBand->rcCapImage.bottom += infoPtr->imageSize.cy; 00892 00893 /* set initial caption text rectangle */ 00894 SetRect (&lpBand->rcCapText, 00895 rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE, 00896 rcBand.right, rcBand.top+lpBand->cxHeader); 00897 } 00898 else { 00899 /* set initial caption text rectangle */ 00900 SetRect (&lpBand->rcCapText, 00901 rcBand.left, lpBand->rcCapImage.bottom, 00902 rcBand.right, rcBand.top+lpBand->cxHeader); 00903 } 00904 00905 /* text is visible */ 00906 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { 00907 lpBand->fDraw |= DRAW_TEXT; 00908 lpBand->rcCapText.bottom = max(lpBand->rcCapText.top, 00909 lpBand->rcCapText.bottom); 00910 } 00911 00912 /* set initial child window rectangle if there is a child */ 00913 if (lpBand->hwndChild) { 00914 int cxBand = rcBand.right - rcBand.left; 00915 xoff = (cxBand - lpBand->cyChild) / 2; 00916 SetRect (&lpBand->rcChild, 00917 rcBand.left + xoff, rcBand.top + lpBand->cxHeader, 00918 rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD); 00919 } 00920 else { 00921 SetRect (&lpBand->rcChild, 00922 rcBand.left, rcBand.top+lpBand->cxHeader, 00923 rcBand.right, rcBand.bottom); 00924 } 00925 00926 if (lpBand->fDraw & NTF_INVALIDATE) { 00927 TRACE("invalidating (%d,%d)-(%d,%d)\n", 00928 rcBand.left, 00929 rcBand.top, 00930 rcBand.right + SEP_WIDTH, 00931 rcBand.bottom + SEP_WIDTH); 00932 lpBand->fDraw &= ~NTF_INVALIDATE; 00933 work = rcBand; 00934 work.bottom += SEP_WIDTH; 00935 work.right += SEP_WIDTH; 00936 InvalidateRect(infoPtr->hwndSelf, &work, TRUE); 00937 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE); 00938 } 00939 00940 } 00941 } 00942 00943 00944 static VOID 00945 REBAR_ForceResize (REBAR_INFO *infoPtr) 00946 /* Function: This changes the size of the REBAR window to that */ 00947 /* calculated by REBAR_Layout. */ 00948 { 00949 INT x, y, width, height; 00950 INT xedge = 0, yedge = 0; 00951 RECT rcSelf; 00952 00953 TRACE("new size [%d x %d]\n", infoPtr->calcSize.cx, infoPtr->calcSize.cy); 00954 00955 if (infoPtr->dwStyle & CCS_NORESIZE) 00956 return; 00957 00958 if (infoPtr->dwStyle & WS_BORDER) 00959 { 00960 xedge = GetSystemMetrics(SM_CXEDGE); 00961 yedge = GetSystemMetrics(SM_CYEDGE); 00962 /* swap for CCS_VERT? */ 00963 } 00964 00965 /* compute rebar window rect in parent client coordinates */ 00966 GetWindowRect(infoPtr->hwndSelf, &rcSelf); 00967 MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->hwndSelf), (LPPOINT)&rcSelf, 2); 00968 translate_rect(infoPtr, &rcSelf, &rcSelf); 00969 00970 height = infoPtr->calcSize.cy + 2*yedge; 00971 if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) { 00972 RECT rcParent; 00973 00974 x = -xedge; 00975 width = infoPtr->calcSize.cx + 2*xedge; 00976 y = 0; /* quiet compiler warning */ 00977 switch ( infoPtr->dwStyle & CCS_LAYOUT_MASK) { 00978 case 0: /* shouldn't happen - see NCCreate */ 00979 case CCS_TOP: 00980 y = ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER) - yedge; 00981 break; 00982 case CCS_NOMOVEY: 00983 y = rcSelf.top; 00984 break; 00985 case CCS_BOTTOM: 00986 GetClientRect(GetParent(infoPtr->hwndSelf), &rcParent); 00987 translate_rect(infoPtr, &rcParent, &rcParent); 00988 y = rcParent.bottom - infoPtr->calcSize.cy - yedge; 00989 break; 00990 } 00991 } 00992 else { 00993 x = rcSelf.left; 00994 /* As on Windows if the CCS_NODIVIDER is not present the control will move 00995 * 2 pixel down after every layout */ 00996 y = rcSelf.top + ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); 00997 width = rcSelf.right - rcSelf.left; 00998 } 00999 01000 TRACE("hwnd %p, style=%08x, setting at (%d,%d) for (%d,%d)\n", 01001 infoPtr->hwndSelf, infoPtr->dwStyle, x, y, width, height); 01002 01003 /* Set flag to ignore next WM_SIZE message and resize the window */ 01004 infoPtr->fStatus |= SELF_RESIZE; 01005 if ((infoPtr->dwStyle & CCS_VERT) == 0) 01006 SetWindowPos(infoPtr->hwndSelf, 0, x, y, width, height, SWP_NOZORDER); 01007 else 01008 SetWindowPos(infoPtr->hwndSelf, 0, y, x, height, width, SWP_NOZORDER); 01009 infoPtr->fStatus &= ~SELF_RESIZE; 01010 } 01011 01012 01013 static VOID 01014 REBAR_MoveChildWindows (const REBAR_INFO *infoPtr, UINT start, UINT endplus) 01015 { 01016 static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; 01017 REBAR_BAND *lpBand; 01018 WCHAR szClassName[40]; 01019 UINT i; 01020 NMREBARCHILDSIZE rbcz; 01021 HDWP deferpos; 01022 01023 if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands))) 01024 ERR("BeginDeferWindowPos returned NULL\n"); 01025 01026 for (i = start; i < endplus; i++) { 01027 lpBand = REBAR_GetBand(infoPtr, i); 01028 01029 if (HIDDENBAND(lpBand)) continue; 01030 if (lpBand->hwndChild) { 01031 TRACE("hwndChild = %p\n", lpBand->hwndChild); 01032 01033 /* Always generate the RBN_CHILDSIZE even if child 01034 did not change */ 01035 rbcz.uBand = i; 01036 rbcz.wID = lpBand->wID; 01037 rbcz.rcChild = lpBand->rcChild; 01038 translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand); 01039 if (infoPtr->dwStyle & CCS_VERT) 01040 rbcz.rcBand.top += lpBand->cxHeader; 01041 else 01042 rbcz.rcBand.left += lpBand->cxHeader; 01043 REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE); 01044 if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) { 01045 TRACE("Child rect changed by NOTIFY for band %u\n", i); 01046 TRACE(" from (%s) to (%s)\n", 01047 wine_dbgstr_rect(&lpBand->rcChild), 01048 wine_dbgstr_rect(&rbcz.rcChild)); 01049 lpBand->rcChild = rbcz.rcChild; /* *** ??? */ 01050 } 01051 01052 /* native (IE4 in "Favorites" frame **1) does: 01053 * SetRect (&rc, -1, -1, -1, -1) 01054 * EqualRect (&rc,band->rc???) 01055 * if ret==0 01056 * CopyRect (band->rc????, &rc) 01057 * set flag outside of loop 01058 */ 01059 01060 GetClassNameW (lpBand->hwndChild, szClassName, sizeof(szClassName)/sizeof(szClassName[0])); 01061 if (!lstrcmpW (szClassName, strComboBox) || 01062 !lstrcmpW (szClassName, WC_COMBOBOXEXW)) { 01063 INT nEditHeight, yPos; 01064 RECT rc; 01065 01066 /* special placement code for combo or comboex box */ 01067 01068 01069 /* get size of edit line */ 01070 GetWindowRect (lpBand->hwndChild, &rc); 01071 nEditHeight = rc.bottom - rc.top; 01072 yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2; 01073 01074 /* center combo box inside child area */ 01075 TRACE("moving child (Combo(Ex)) %p to (%d,%d) for (%d,%d)\n", 01076 lpBand->hwndChild, 01077 lpBand->rcChild.left, yPos, 01078 lpBand->rcChild.right - lpBand->rcChild.left, 01079 nEditHeight); 01080 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, 01081 lpBand->rcChild.left, 01082 /*lpBand->rcChild.top*/ yPos, 01083 lpBand->rcChild.right - lpBand->rcChild.left, 01084 nEditHeight, 01085 SWP_NOZORDER); 01086 if (!deferpos) 01087 ERR("DeferWindowPos returned NULL\n"); 01088 } 01089 else { 01090 TRACE("moving child (Other) %p to (%d,%d) for (%d,%d)\n", 01091 lpBand->hwndChild, 01092 lpBand->rcChild.left, lpBand->rcChild.top, 01093 lpBand->rcChild.right - lpBand->rcChild.left, 01094 lpBand->rcChild.bottom - lpBand->rcChild.top); 01095 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, 01096 lpBand->rcChild.left, 01097 lpBand->rcChild.top, 01098 lpBand->rcChild.right - lpBand->rcChild.left, 01099 lpBand->rcChild.bottom - lpBand->rcChild.top, 01100 SWP_NOZORDER); 01101 if (!deferpos) 01102 ERR("DeferWindowPos returned NULL\n"); 01103 } 01104 } 01105 } 01106 if (!EndDeferWindowPos(deferpos)) 01107 ERR("EndDeferWindowPos returned NULL\n"); 01108 01109 if (infoPtr->DoRedraw) 01110 UpdateWindow (infoPtr->hwndSelf); 01111 01112 /* native (from **1 above) does: 01113 * UpdateWindow(rebar) 01114 * REBAR_ForceResize 01115 * RBN_HEIGHTCHANGE if necessary 01116 * if ret from any EqualRect was 0 01117 * Goto "BeginDeferWindowPos" 01118 */ 01119 01120 } 01121 01122 /* Returns the next visible band (the first visible band in [i+1; infoPtr->uNumBands) ) 01123 * or infoPtr->uNumBands if none */ 01124 static int next_visible(const REBAR_INFO *infoPtr, int i) 01125 { 01126 int n; 01127 for (n = i + 1; n < infoPtr->uNumBands; n++) 01128 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n))) 01129 break; 01130 return n; 01131 } 01132 01133 /* Returns the previous visible band (the last visible band in [0; i) ) 01134 * or -1 if none */ 01135 static int prev_visible(const REBAR_INFO *infoPtr, int i) 01136 { 01137 int n; 01138 for (n = i - 1; n >= 0; n--) 01139 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n))) 01140 break; 01141 return n; 01142 } 01143 01144 /* Returns the first visible band or infoPtr->uNumBands if none */ 01145 static int first_visible(const REBAR_INFO *infoPtr) 01146 { 01147 return next_visible(infoPtr, -1); /* this works*/ 01148 } 01149 01150 /* Returns the first visible band for the given row (or iBand if none) */ 01151 static int get_row_begin_for_band(const REBAR_INFO *infoPtr, INT iBand) 01152 { 01153 int iLastBand = iBand; 01154 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow; 01155 while ((iBand = prev_visible(infoPtr, iBand)) >= 0) { 01156 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow) 01157 break; 01158 else 01159 iLastBand = iBand; 01160 } 01161 return iLastBand; 01162 } 01163 01164 /* Returns the first visible band for the next row (or infoPtr->uNumBands if none) */ 01165 static int get_row_end_for_band(const REBAR_INFO *infoPtr, INT iBand) 01166 { 01167 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow; 01168 while ((iBand = next_visible(infoPtr, iBand)) < infoPtr->uNumBands) 01169 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow) 01170 break; 01171 return iBand; 01172 } 01173 01174 /* Compute the rcBand.{left,right} from the cxEffective bands widths computed earlier. 01175 * iBeginBand must be visible */ 01176 static void REBAR_SetRowRectsX(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand) 01177 { 01178 int xPos = 0, i; 01179 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01180 { 01181 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 01182 if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) { 01183 lpBand->fDraw |= NTF_INVALIDATE; 01184 TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective); 01185 lpBand->rcBand.left = xPos; 01186 lpBand->rcBand.right = xPos + lpBand->cxEffective; 01187 } 01188 xPos += lpBand->cxEffective + SEP_WIDTH; 01189 } 01190 } 01191 01192 /* The rationale of this function is probably as follows: if we have some space 01193 * to distribute we want to add it to a band on the right. However we don't want 01194 * to unminimize a minimized band so we search for a band that is big enough. 01195 * For some reason "big enough" is defined as bigger than the minimum size of the 01196 * first band in the row 01197 */ 01198 static REBAR_BAND *REBAR_FindBandToGrow(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand) 01199 { 01200 INT cxMinFirstBand = 0, i; 01201 01202 cxMinFirstBand = REBAR_GetBand(infoPtr, iBeginBand)->cxMinBand; 01203 01204 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 01205 if (REBAR_GetBand(infoPtr, i)->cxEffective > cxMinFirstBand && 01206 !(REBAR_GetBand(infoPtr, i)->fStyle & RBBS_FIXEDSIZE)) 01207 break; 01208 01209 if (i < iBeginBand) 01210 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 01211 if (REBAR_GetBand(infoPtr, i)->cxMinBand == cxMinFirstBand) 01212 break; 01213 01214 TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i); 01215 return REBAR_GetBand(infoPtr, i); 01216 } 01217 01218 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the right */ 01219 static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) 01220 { 01221 REBAR_BAND *lpBand; 01222 INT width, i; 01223 01224 TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink); 01225 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 01226 { 01227 lpBand = REBAR_GetBand(infoPtr, i); 01228 01229 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand); 01230 cxShrink -= lpBand->cxEffective - width; 01231 lpBand->cxEffective = width; 01232 if (bEnforce && lpBand->cx > lpBand->cxEffective) 01233 lpBand->cx = lpBand->cxEffective; 01234 if (cxShrink == 0) 01235 break; 01236 } 01237 return cxShrink; 01238 } 01239 01240 01241 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the left. 01242 * iBeginBand must be visible */ 01243 static int REBAR_ShrinkBandsLTR(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) 01244 { 01245 REBAR_BAND *lpBand; 01246 INT width, i; 01247 01248 TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink); 01249 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01250 { 01251 lpBand = REBAR_GetBand(infoPtr, i); 01252 01253 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand); 01254 cxShrink -= lpBand->cxEffective - width; 01255 lpBand->cxEffective = width; 01256 if (bEnforce) 01257 lpBand->cx = lpBand->cxEffective; 01258 if (cxShrink == 0) 01259 break; 01260 } 01261 return cxShrink; 01262 } 01263 01264 /* Tries to move a band to a given offset within a row. */ 01265 static int REBAR_MoveBandToRowOffset(REBAR_INFO *infoPtr, INT iBand, INT iFirstBand, 01266 INT iLastBand, INT xOff, BOOL reorder) 01267 { 01268 REBAR_BAND *insertBand = REBAR_GetBand(infoPtr, iBand); 01269 int xPos = 0, i; 01270 const BOOL setBreak = REBAR_GetBand(infoPtr, iFirstBand)->fStyle & RBBS_BREAK; 01271 01272 /* Find the band's new position */ 01273 if(reorder) 01274 { 01275 /* Used during an LR band reorder drag */ 01276 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i)) 01277 { 01278 if(xPos > xOff) 01279 break; 01280 xPos += REBAR_GetBand(infoPtr, i)->cxEffective + SEP_WIDTH; 01281 } 01282 } 01283 else 01284 { 01285 /* Used during a UD band insertion drag */ 01286 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i)) 01287 { 01288 const REBAR_BAND *band = REBAR_GetBand(infoPtr, i); 01289 if(xPos + band->cxMinBand / 2 > xOff) 01290 break; 01291 xPos += band->cxEffective + SEP_WIDTH; 01292 } 01293 } 01294 01295 /* Move the band to its new position */ 01296 DPA_DeletePtr(infoPtr->bands, iBand); 01297 if(i > iBand) 01298 i--; 01299 DPA_InsertPtr(infoPtr->bands, i, insertBand); 01300 01301 /* Ensure only the last band has the RBBS_BREAK flag set */ 01302 insertBand->fStyle &= ~RBBS_BREAK; 01303 if(setBreak) 01304 REBAR_GetBand(infoPtr, iFirstBand)->fStyle |= RBBS_BREAK; 01305 01306 /* Return the currently grabbed band */ 01307 if(infoPtr->iGrabbedBand == iBand) 01308 { 01309 infoPtr->iGrabbedBand = i; 01310 return i; 01311 } 01312 else return -1; 01313 } 01314 01315 /* Set the heights of the visible bands in [iBeginBand; iEndBand) to the max height. iBeginBand must be visible */ 01316 static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart) 01317 { 01318 REBAR_BAND *lpBand; 01319 int yMaxHeight = 0; 01320 int yPos = yStart; 01321 int row = REBAR_GetBand(infoPtr, iBeginBand)->iRow; 01322 int i; 01323 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01324 { 01325 lpBand = REBAR_GetBand(infoPtr, i); 01326 lpBand->cyRowSoFar = yMaxHeight; 01327 yMaxHeight = max(yMaxHeight, lpBand->cyMinBand); 01328 } 01329 TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight); 01330 01331 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01332 { 01333 lpBand = REBAR_GetBand(infoPtr, i); 01334 /* we may be called for multiple rows if RBS_VARHEIGHT not set */ 01335 if (lpBand->iRow != row) { 01336 yPos += yMaxHeight + SEP_WIDTH; 01337 row = lpBand->iRow; 01338 } 01339 01340 if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) { 01341 lpBand->fDraw |= NTF_INVALIDATE; 01342 lpBand->rcBand.top = yPos; 01343 lpBand->rcBand.bottom = yPos + yMaxHeight; 01344 TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand)); 01345 } 01346 } 01347 return yPos + yMaxHeight; 01348 } 01349 01350 /* Layout the row [iBeginBand; iEndBand). iBeginBand must be visible */ 01351 static void REBAR_LayoutRow(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos) 01352 { 01353 REBAR_BAND *lpBand; 01354 int i, extra; 01355 int width = 0; 01356 01357 TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx); 01358 for (i = iBeginBand; i < iEndBand; i++) 01359 REBAR_GetBand(infoPtr, i)->iRow = *piRow; 01360 01361 /* compute the extra space */ 01362 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01363 { 01364 lpBand = REBAR_GetBand(infoPtr, i); 01365 if (i > iBeginBand) 01366 width += SEP_WIDTH; 01367 lpBand->cxEffective = max(lpBand->cxMinBand, lpBand->cx); 01368 width += lpBand->cxEffective; 01369 } 01370 01371 extra = cx - width; 01372 TRACE("Extra space: %d\n", extra); 01373 if (extra < 0) { 01374 int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE); 01375 if (ret > 0 && next_visible(infoPtr, iBeginBand) != iEndBand) /* one band may be longer than expected... */ 01376 ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra); 01377 } else 01378 if (extra > 0) { 01379 lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand); 01380 lpBand->cxEffective += extra; 01381 } 01382 01383 REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand); 01384 if (infoPtr->dwStyle & RBS_VARHEIGHT) 01385 { 01386 if (*piRow > 0) 01387 *pyPos += SEP_WIDTH; 01388 *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos); 01389 } 01390 (*piRow)++; 01391 } 01392 01393 static VOID 01394 REBAR_Layout(REBAR_INFO *infoPtr) 01395 { 01396 REBAR_BAND *lpBand; 01397 RECT rcAdj; 01398 SIZE oldSize; 01399 INT adjcx, i; 01400 INT rowstart; 01401 INT row = 0; 01402 INT xMin, yPos; 01403 01404 if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL) 01405 GetClientRect(infoPtr->hwndSelf, &rcAdj); 01406 else 01407 GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj); 01408 TRACE("adjustment rect is (%s)\n", wine_dbgstr_rect(&rcAdj)); 01409 01410 adjcx = get_rect_cx(infoPtr, &rcAdj); 01411 01412 if (infoPtr->uNumBands == 0) { 01413 TRACE("No bands - setting size to (0,%d), vert: %x\n", adjcx, infoPtr->dwStyle & CCS_VERT); 01414 infoPtr->calcSize.cx = adjcx; 01415 /* the calcSize.cy won't change for a 0 band rebar */ 01416 infoPtr->uNumRows = 0; 01417 REBAR_ForceResize(infoPtr); 01418 return; 01419 } 01420 01421 yPos = 0; 01422 xMin = 0; 01423 rowstart = first_visible(infoPtr); 01424 /* divide rows */ 01425 for (i = rowstart; i < infoPtr->uNumBands; i = next_visible(infoPtr, i)) 01426 { 01427 lpBand = REBAR_GetBand(infoPtr, i); 01428 01429 if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->cxMinBand > adjcx)) { 01430 TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1); 01431 REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos); 01432 rowstart = i; 01433 xMin = 0; 01434 } 01435 else 01436 xMin += SEP_WIDTH; 01437 01438 xMin += lpBand->cxMinBand; 01439 } 01440 if (rowstart < infoPtr->uNumBands) 01441 REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos); 01442 01443 if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) 01444 yPos = REBAR_SetBandsHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, 0); 01445 01446 infoPtr->uNumRows = row; 01447 01448 if (infoPtr->dwStyle & CCS_VERT) 01449 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); 01450 else 01451 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands); 01452 /* now compute size of Rebar itself */ 01453 oldSize = infoPtr->calcSize; 01454 01455 infoPtr->calcSize.cx = adjcx; 01456 infoPtr->calcSize.cy = yPos; 01457 TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n", 01458 infoPtr->calcSize.cx, infoPtr->calcSize.cy, 01459 oldSize.cx, oldSize.cy); 01460 01461 REBAR_DumpBand (infoPtr); 01462 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); 01463 REBAR_ForceResize (infoPtr); 01464 01465 /* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE 01466 * and does another ForceResize */ 01467 if (oldSize.cy != infoPtr->calcSize.cy) 01468 { 01469 NMHDR heightchange; 01470 REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE); 01471 REBAR_AutoSize(infoPtr, FALSE); 01472 } 01473 } 01474 01475 /* iBeginBand must be visible */ 01476 static int 01477 REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged) 01478 { 01479 int cyBandsOld; 01480 int cyBandsNew = 0; 01481 int i; 01482 01483 TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra); 01484 01485 cyBandsOld = REBAR_GetBand(infoPtr, iBeginBand)->rcBand.bottom - 01486 REBAR_GetBand(infoPtr, iBeginBand)->rcBand.top; 01487 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 01488 { 01489 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 01490 int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra; 01491 int cyChild = round_child_height(lpBand, cyMaxChild); 01492 01493 if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) 01494 { 01495 TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild); 01496 *fChanged = TRUE; 01497 lpBand->cyChild = cyChild; 01498 lpBand->fDraw |= NTF_INVALIDATE; 01499 update_min_band_height(infoPtr, lpBand); 01500 } 01501 cyBandsNew = max(cyBandsNew, lpBand->cyMinBand); 01502 } 01503 return cyBandsNew - cyBandsOld; 01504 } 01505 01506 /* worker function for RB_SIZETORECT and RBS_AUTOSIZE */ 01507 static VOID 01508 REBAR_SizeToHeight(REBAR_INFO *infoPtr, int height) 01509 { 01510 int extra = height - infoPtr->calcSize.cy; /* may be negative */ 01511 BOOL fChanged = FALSE; 01512 UINT uNumRows = infoPtr->uNumRows; 01513 int i; 01514 01515 if (uNumRows == 0) /* avoid division by 0 */ 01516 return; 01517 01518 /* That's not exactly what Windows does but should be similar */ 01519 01520 /* Pass one: break-up/glue rows */ 01521 if (extra > 0) 01522 { 01523 for (i = prev_visible(infoPtr, infoPtr->uNumBands); i > 0; i = prev_visible(infoPtr, i)) 01524 { 01525 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 01526 int cyBreakExtra; /* additional cy for the rebar after a RBBS_BREAK on this band */ 01527 01528 height = lpBand->rcBand.bottom - lpBand->rcBand.top; 01529 01530 if (infoPtr->dwStyle & RBS_VARHEIGHT) 01531 cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/ 01532 else 01533 cyBreakExtra = height; /* 'height' => 'height' + 'height'*/ 01534 cyBreakExtra += SEP_WIDTH; 01535 01536 if (extra <= cyBreakExtra / 2) 01537 break; 01538 01539 if (!(lpBand->fStyle & RBBS_BREAK)) 01540 { 01541 TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra); 01542 lpBand->fStyle |= RBBS_BREAK; 01543 lpBand->fDraw |= NTF_INVALIDATE; 01544 fChanged = TRUE; 01545 extra -= cyBreakExtra; 01546 uNumRows++; 01547 /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */ 01548 if (infoPtr->dwStyle & RBS_VARHEIGHT) 01549 lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->cyMinBand; 01550 } 01551 } 01552 } 01553 /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */ 01554 01555 /* Pass two: increase/decrease control height */ 01556 if (infoPtr->dwStyle & RBS_VARHEIGHT) 01557 { 01558 int i = first_visible(infoPtr); 01559 int iRow = 0; 01560 while (i < infoPtr->uNumBands) 01561 { 01562 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 01563 int extraForRow = extra / (int)(uNumRows - iRow); 01564 int rowEnd; 01565 01566 /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */ 01567 for (rowEnd = next_visible(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_visible(infoPtr, rowEnd)) 01568 if (REBAR_GetBand(infoPtr, rowEnd)->iRow != lpBand->iRow || 01569 REBAR_GetBand(infoPtr, rowEnd)->fStyle & RBBS_BREAK) 01570 break; 01571 01572 extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged); 01573 TRACE("extra = %d\n", extra); 01574 i = rowEnd; 01575 iRow++; 01576 } 01577 } 01578 else 01579 REBAR_SizeChildrenToHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged); 01580 01581 if (fChanged) 01582 REBAR_Layout(infoPtr); 01583 } 01584 01585 static VOID 01586 REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout) 01587 { 01588 RECT rc, rcNew; 01589 NMRBAUTOSIZE autosize; 01590 01591 if (needsLayout) 01592 REBAR_Layout(infoPtr); 01593 GetClientRect(infoPtr->hwndSelf, &rc); 01594 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, &rc)); 01595 GetClientRect(infoPtr->hwndSelf, &rcNew); 01596 01597 GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget); 01598 autosize.fChanged = (memcmp(&rc, &rcNew, sizeof(RECT)) == 0); 01599 autosize.rcTarget = rc; 01600 autosize.rcActual = rcNew; 01601 REBAR_Notify((NMHDR *)&autosize, infoPtr, RBN_AUTOSIZE); 01602 } 01603 01604 static VOID 01605 REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 01606 /* Function: This routine evaluates the band specs supplied */ 01607 /* by the user and updates the following 5 fields in */ 01608 /* the internal band structure: cxHeader, cyHeader, cxMinBand, cyMinBand, fStatus */ 01609 { 01610 UINT header=0; 01611 UINT textheight=0, imageheight = 0; 01612 UINT i, nonfixed; 01613 REBAR_BAND *tBand; 01614 01615 lpBand->fStatus = 0; 01616 lpBand->cxMinBand = 0; 01617 lpBand->cyMinBand = 0; 01618 01619 /* Data coming in from users into the cx... and cy... fields */ 01620 /* may be bad, just garbage, because the user never clears */ 01621 /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */ 01622 /* along if the fields exist in the input area. Here we must */ 01623 /* determine if the data is valid. I have no idea how MS does */ 01624 /* the validation, but it does because the RB_GETBANDINFO */ 01625 /* returns a 0 when I know the sample program passed in an */ 01626 /* address. Here I will use the algorithm that if the value */ 01627 /* is greater than 65535 then it is bad and replace it with */ 01628 /* a zero. Feel free to improve the algorithm. - GA 12/2000 */ 01629 if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0; 01630 if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0; 01631 if (lpBand->cx > 65535) lpBand->cx = 0; 01632 if (lpBand->cyChild > 65535) lpBand->cyChild = 0; 01633 if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0; 01634 if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0; 01635 if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0; 01636 01637 /* TODO : we could try return to the caller if a value changed so that */ 01638 /* a REBAR_Layout is needed. Till now the caller should call it */ 01639 /* it always (we should also check what native does) */ 01640 01641 /* Header is where the image, text and gripper exist */ 01642 /* in the band and precede the child window. */ 01643 01644 /* count number of non-FIXEDSIZE and non-Hidden bands */ 01645 nonfixed = 0; 01646 for (i=0; i<infoPtr->uNumBands; i++){ 01647 tBand = REBAR_GetBand(infoPtr, i); 01648 if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE)) 01649 nonfixed++; 01650 } 01651 01652 /* calculate gripper rectangle */ 01653 if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) && 01654 ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) || 01655 ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1))) 01656 ) { 01657 lpBand->fStatus |= HAS_GRIPPER; 01658 if (infoPtr->dwStyle & CCS_VERT) 01659 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) 01660 header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER); 01661 else 01662 header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER); 01663 else 01664 header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH); 01665 /* Always have 4 pixels before anything else */ 01666 header += REBAR_ALWAYS_SPACE; 01667 } 01668 01669 /* image is visible */ 01670 if (lpBand->iImage != -1 && (infoPtr->himl)) { 01671 lpBand->fStatus |= HAS_IMAGE; 01672 if (infoPtr->dwStyle & CCS_VERT) { 01673 header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE); 01674 imageheight = infoPtr->imageSize.cx + 4; 01675 } 01676 else { 01677 header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE); 01678 imageheight = infoPtr->imageSize.cy + 4; 01679 } 01680 } 01681 01682 /* text is visible */ 01683 if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) && 01684 !(lpBand->fStyle & RBBS_HIDETITLE)) { 01685 HDC hdc = GetDC (0); 01686 HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); 01687 SIZE size; 01688 01689 lpBand->fStatus |= HAS_TEXT; 01690 GetTextExtentPoint32W (hdc, lpBand->lpText, 01691 lstrlenW (lpBand->lpText), &size); 01692 header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT)); 01693 textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy; 01694 01695 SelectObject (hdc, hOldFont); 01696 ReleaseDC (0, hdc); 01697 } 01698 01699 /* if no gripper but either image or text, then leave space */ 01700 if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) && 01701 !(lpBand->fStatus & HAS_GRIPPER)) { 01702 header += REBAR_ALWAYS_SPACE; 01703 } 01704 01705 /* check if user overrode the header value */ 01706 if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER)) 01707 lpBand->cxHeader = header; 01708 lpBand->cyHeader = max(textheight, imageheight); 01709 01710 /* Now compute minimum size of child window */ 01711 update_min_band_height(infoPtr, lpBand); /* update lpBand->cyMinBand from cyHeader and cyChild*/ 01712 01713 lpBand->cxMinBand = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD; 01714 if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal) 01715 lpBand->cxMinBand += CHEVRON_WIDTH; 01716 } 01717 01718 static UINT 01719 REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBand) 01720 /* Function: This routine copies the supplied values from */ 01721 /* user input (lprbbi) to the internal band structure. */ 01722 /* It returns the mask of what changed. */ 01723 { 01724 UINT uChanged = 0x0; 01725 01726 lpBand->fMask |= lprbbi->fMask; 01727 01728 if( (lprbbi->fMask & RBBIM_STYLE) && 01729 (lpBand->fStyle != lprbbi->fStyle ) ) 01730 { 01731 lpBand->fStyle = lprbbi->fStyle; 01732 uChanged |= RBBIM_STYLE; 01733 } 01734 01735 if( (lprbbi->fMask & RBBIM_COLORS) && 01736 ( ( lpBand->clrFore != lprbbi->clrFore ) || 01737 ( lpBand->clrBack != lprbbi->clrBack ) ) ) 01738 { 01739 lpBand->clrFore = lprbbi->clrFore; 01740 lpBand->clrBack = lprbbi->clrBack; 01741 uChanged |= RBBIM_COLORS; 01742 } 01743 01744 if( (lprbbi->fMask & RBBIM_IMAGE) && 01745 ( lpBand->iImage != lprbbi->iImage ) ) 01746 { 01747 lpBand->iImage = lprbbi->iImage; 01748 uChanged |= RBBIM_IMAGE; 01749 } 01750 01751 if( (lprbbi->fMask & RBBIM_CHILD) && 01752 (lprbbi->hwndChild != lpBand->hwndChild ) ) 01753 { 01754 if (lprbbi->hwndChild) { 01755 lpBand->hwndChild = lprbbi->hwndChild; 01756 lpBand->hwndPrevParent = 01757 SetParent (lpBand->hwndChild, hwnd); 01758 /* below in trace from WinRAR */ 01759 ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL); 01760 /* above in trace from WinRAR */ 01761 } 01762 else { 01763 TRACE("child: %p prev parent: %p\n", 01764 lpBand->hwndChild, lpBand->hwndPrevParent); 01765 lpBand->hwndChild = 0; 01766 lpBand->hwndPrevParent = 0; 01767 } 01768 uChanged |= RBBIM_CHILD; 01769 } 01770 01771 if( (lprbbi->fMask & RBBIM_CHILDSIZE) && 01772 ( (lpBand->cxMinChild != lprbbi->cxMinChild) || 01773 (lpBand->cyMinChild != lprbbi->cyMinChild ) || 01774 ( (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) && 01775 ( (lpBand->cyChild != lprbbi->cyChild ) || 01776 (lpBand->cyMaxChild != lprbbi->cyMaxChild ) || 01777 (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) || 01778 ( (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE) && 01779 ( (lpBand->cyChild || 01780 lpBand->cyMaxChild || 01781 lpBand->cyIntegral ) ) ) ) ) 01782 { 01783 lpBand->cxMinChild = lprbbi->cxMinChild; 01784 lpBand->cyMinChild = lprbbi->cyMinChild; 01785 /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */ 01786 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 01787 lpBand->cyMaxChild = lprbbi->cyMaxChild; 01788 lpBand->cyIntegral = lprbbi->cyIntegral; 01789 01790 lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild); /* make (cyChild - cyMinChild) a multiple of cyIntergral */ 01791 } 01792 else { 01793 lpBand->cyChild = lpBand->cyMinChild; 01794 lpBand->cyMaxChild = 0x7fffffff; 01795 lpBand->cyIntegral = 0; 01796 } 01797 uChanged |= RBBIM_CHILDSIZE; 01798 } 01799 01800 if( (lprbbi->fMask & RBBIM_SIZE) && 01801 (lpBand->cx != lprbbi->cx ) ) 01802 { 01803 lpBand->cx = lprbbi->cx; 01804 uChanged |= RBBIM_SIZE; 01805 } 01806 01807 if( (lprbbi->fMask & RBBIM_BACKGROUND) && 01808 ( lpBand->hbmBack != lprbbi->hbmBack ) ) 01809 { 01810 lpBand->hbmBack = lprbbi->hbmBack; 01811 uChanged |= RBBIM_BACKGROUND; 01812 } 01813 01814 if( (lprbbi->fMask & RBBIM_ID) && 01815 (lpBand->wID != lprbbi->wID ) ) 01816 { 01817 lpBand->wID = lprbbi->wID; 01818 uChanged |= RBBIM_ID; 01819 } 01820 01821 /* check for additional data */ 01822 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE) { 01823 if( (lprbbi->fMask & RBBIM_IDEALSIZE) && 01824 ( lpBand->cxIdeal != lprbbi->cxIdeal ) ) 01825 { 01826 lpBand->cxIdeal = lprbbi->cxIdeal; 01827 uChanged |= RBBIM_IDEALSIZE; 01828 } 01829 01830 if( (lprbbi->fMask & RBBIM_LPARAM) && 01831 (lpBand->lParam != lprbbi->lParam ) ) 01832 { 01833 lpBand->lParam = lprbbi->lParam; 01834 uChanged |= RBBIM_LPARAM; 01835 } 01836 01837 if( (lprbbi->fMask & RBBIM_HEADERSIZE) && 01838 (lpBand->cxHeader != lprbbi->cxHeader ) ) 01839 { 01840 lpBand->cxHeader = lprbbi->cxHeader; 01841 lpBand->fStyle |= RBBS_UNDOC_FIXEDHEADER; 01842 uChanged |= RBBIM_HEADERSIZE; 01843 } 01844 } 01845 01846 return uChanged; 01847 } 01848 01849 static LRESULT REBAR_EraseBkGnd (const REBAR_INFO *infoPtr, HDC hdc) 01850 /* Function: This erases the background rectangle by drawing */ 01851 /* each band with its background color (or the default) and */ 01852 /* draws each bands right separator if necessary. The row */ 01853 /* separators are drawn on the first band of the next row. */ 01854 { 01855 REBAR_BAND *lpBand; 01856 UINT i; 01857 INT oldrow; 01858 RECT cr; 01859 COLORREF old = CLR_NONE, new; 01860 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 01861 01862 GetClientRect (infoPtr->hwndSelf, &cr); 01863 01864 oldrow = -1; 01865 for(i=0; i<infoPtr->uNumBands; i++) { 01866 RECT rcBand; 01867 lpBand = REBAR_GetBand(infoPtr, i); 01868 if (HIDDENBAND(lpBand)) continue; 01869 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 01870 01871 /* draw band separator between rows */ 01872 if (lpBand->iRow != oldrow) { 01873 oldrow = lpBand->iRow; 01874 if (infoPtr->dwStyle & RBS_BANDBORDERS) { 01875 RECT rcRowSep; 01876 rcRowSep = rcBand; 01877 if (infoPtr->dwStyle & CCS_VERT) { 01878 rcRowSep.right += SEP_WIDTH_SIZE; 01879 rcRowSep.bottom = infoPtr->calcSize.cx; 01880 if (theme) 01881 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL); 01882 else 01883 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT); 01884 } 01885 else { 01886 rcRowSep.bottom += SEP_WIDTH_SIZE; 01887 rcRowSep.right = infoPtr->calcSize.cx; 01888 if (theme) 01889 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL); 01890 else 01891 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM); 01892 } 01893 TRACE ("drawing band separator bottom (%s)\n", 01894 wine_dbgstr_rect(&rcRowSep)); 01895 } 01896 } 01897 01898 /* draw band separator between bands in a row */ 01899 if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) { 01900 RECT rcSep; 01901 rcSep = rcBand; 01902 if (infoPtr->dwStyle & CCS_VERT) { 01903 rcSep.bottom = rcSep.top; 01904 rcSep.top -= SEP_WIDTH_SIZE; 01905 if (theme) 01906 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL); 01907 else 01908 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM); 01909 } 01910 else { 01911 rcSep.right = rcSep.left; 01912 rcSep.left -= SEP_WIDTH_SIZE; 01913 if (theme) 01914 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL); 01915 else 01916 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT); 01917 } 01918 TRACE("drawing band separator right (%s)\n", 01919 wine_dbgstr_rect(&rcSep)); 01920 } 01921 01922 /* draw the actual background */ 01923 if (lpBand->clrBack != CLR_NONE) { 01924 new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace : 01925 lpBand->clrBack; 01926 #if GLATESTING 01927 /* testing only - make background green to see it */ 01928 new = RGB(0,128,0); 01929 #endif 01930 } 01931 else { 01932 /* In the absence of documentation for Rebar vs. CLR_NONE, 01933 * we will use the default BtnFace color. Note documentation 01934 * exists for Listview and Imagelist. 01935 */ 01936 new = infoPtr->clrBtnFace; 01937 #if GLATESTING 01938 /* testing only - make background green to see it */ 01939 new = RGB(0,128,0); 01940 #endif 01941 } 01942 01943 if (theme) 01944 { 01945 /* When themed, the background color is ignored (but not a 01946 * background bitmap */ 01947 DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand); 01948 } 01949 else 01950 { 01951 old = SetBkColor (hdc, new); 01952 TRACE("%s background color=0x%06x, band %s\n", 01953 (lpBand->clrBack == CLR_NONE) ? "none" : 01954 ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""), 01955 GetBkColor(hdc), wine_dbgstr_rect(&rcBand)); 01956 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0); 01957 if (lpBand->clrBack != CLR_NONE) 01958 SetBkColor (hdc, old); 01959 } 01960 } 01961 return TRUE; 01962 } 01963 01964 static void 01965 REBAR_InternalHitTest (const REBAR_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pBand) 01966 { 01967 REBAR_BAND *lpBand; 01968 RECT rect; 01969 UINT iCount; 01970 01971 GetClientRect (infoPtr->hwndSelf, &rect); 01972 01973 *pFlags = RBHT_NOWHERE; 01974 if (PtInRect (&rect, *lpPt)) 01975 { 01976 if (infoPtr->uNumBands == 0) { 01977 *pFlags = RBHT_NOWHERE; 01978 if (pBand) 01979 *pBand = -1; 01980 TRACE("NOWHERE\n"); 01981 return; 01982 } 01983 else { 01984 /* somewhere inside */ 01985 for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) { 01986 RECT rcBand; 01987 lpBand = REBAR_GetBand(infoPtr, iCount); 01988 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 01989 if (HIDDENBAND(lpBand)) continue; 01990 if (PtInRect (&rcBand, *lpPt)) { 01991 if (pBand) 01992 *pBand = iCount; 01993 if (PtInRect (&lpBand->rcGripper, *lpPt)) { 01994 *pFlags = RBHT_GRABBER; 01995 TRACE("ON GRABBER %d\n", iCount); 01996 return; 01997 } 01998 else if (PtInRect (&lpBand->rcCapImage, *lpPt)) { 01999 *pFlags = RBHT_CAPTION; 02000 TRACE("ON CAPTION %d\n", iCount); 02001 return; 02002 } 02003 else if (PtInRect (&lpBand->rcCapText, *lpPt)) { 02004 *pFlags = RBHT_CAPTION; 02005 TRACE("ON CAPTION %d\n", iCount); 02006 return; 02007 } 02008 else if (PtInRect (&lpBand->rcChild, *lpPt)) { 02009 *pFlags = RBHT_CLIENT; 02010 TRACE("ON CLIENT %d\n", iCount); 02011 return; 02012 } 02013 else if (PtInRect (&lpBand->rcChevron, *lpPt)) { 02014 *pFlags = RBHT_CHEVRON; 02015 TRACE("ON CHEVRON %d\n", iCount); 02016 return; 02017 } 02018 else { 02019 *pFlags = RBHT_NOWHERE; 02020 TRACE("NOWHERE %d\n", iCount); 02021 return; 02022 } 02023 } 02024 } 02025 02026 *pFlags = RBHT_NOWHERE; 02027 if (pBand) 02028 *pBand = -1; 02029 02030 TRACE("NOWHERE\n"); 02031 return; 02032 } 02033 } 02034 else { 02035 *pFlags = RBHT_NOWHERE; 02036 if (pBand) 02037 *pBand = -1; 02038 TRACE("NOWHERE\n"); 02039 return; 02040 } 02041 } 02042 02043 static void 02044 REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) 02045 /* Function: This will implement the functionality of a */ 02046 /* Gripper drag within a row. It will not implement "out- */ 02047 /* of-row" drags. (They are detected and handled in */ 02048 /* REBAR_MouseMove.) */ 02049 { 02050 REBAR_BAND *hitBand; 02051 INT iHitBand, iRowBegin, iRowEnd; 02052 INT movement, xBand, cxLeft = 0; 02053 BOOL shrunkBands = FALSE; 02054 02055 iHitBand = infoPtr->iGrabbedBand; 02056 iRowBegin = get_row_begin_for_band(infoPtr, iHitBand); 02057 iRowEnd = get_row_end_for_band(infoPtr, iHitBand); 02058 hitBand = REBAR_GetBand(infoPtr, iHitBand); 02059 02060 xBand = hitBand->rcBand.left; 02061 movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x) 02062 - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset); 02063 02064 /* Dragging the first band in a row cannot cause shrinking */ 02065 if(iHitBand != iRowBegin) 02066 { 02067 if (movement < 0) { 02068 cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE); 02069 02070 if(cxLeft < -movement) 02071 { 02072 hitBand->cxEffective += -movement - cxLeft; 02073 hitBand->cx = hitBand->cxEffective; 02074 shrunkBands = TRUE; 02075 } 02076 02077 } else if (movement > 0) { 02078 02079 cxLeft = movement; 02080 if (prev_visible(infoPtr, iHitBand) >= 0) 02081 cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE); 02082 02083 if(cxLeft < movement) 02084 { 02085 REBAR_BAND *lpPrev = REBAR_GetBand(infoPtr, prev_visible(infoPtr, iHitBand)); 02086 lpPrev->cxEffective += movement - cxLeft; 02087 lpPrev->cx = hitBand->cxEffective; 02088 shrunkBands = TRUE; 02089 } 02090 02091 } 02092 } 02093 02094 if(!shrunkBands) 02095 { 02096 /* It was not possible to move the band by shrinking bands. 02097 * Try relocating the band instead. */ 02098 REBAR_MoveBandToRowOffset(infoPtr, iHitBand, iRowBegin, 02099 iRowEnd, xBand + movement, TRUE); 02100 } 02101 02102 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 02103 if (infoPtr->dwStyle & CCS_VERT) 02104 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); 02105 else 02106 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands); 02107 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 02108 } 02109 02110 static void 02111 REBAR_HandleUDDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) 02112 { 02113 INT yOff = (infoPtr->dwStyle & CCS_VERT) ? ptsmove->x : ptsmove->y; 02114 INT iHitBand, iRowBegin, iNextRowBegin; 02115 REBAR_BAND *hitBand, *rowBeginBand; 02116 02117 if(infoPtr->uNumBands <= 0) 02118 ERR("There are no bands in this rebar\n"); 02119 02120 /* Up/down dragging can only occur when there is more than one 02121 * band in the rebar */ 02122 if(infoPtr->uNumBands <= 1) 02123 return; 02124 02125 iHitBand = infoPtr->iGrabbedBand; 02126 hitBand = REBAR_GetBand(infoPtr, iHitBand); 02127 02128 /* If we're taking a band that has the RBBS_BREAK style set, this 02129 * style needs to be reapplied to the band that is going to become 02130 * the new start of the row. */ 02131 if((hitBand->fStyle & RBBS_BREAK) && 02132 (iHitBand < infoPtr->uNumBands - 1)) 02133 REBAR_GetBand(infoPtr, iHitBand + 1)->fStyle |= RBBS_BREAK; 02134 02135 if(yOff < 0) 02136 { 02137 /* Place the band above the current top row */ 02138 DPA_DeletePtr(infoPtr->bands, iHitBand); 02139 hitBand->fStyle &= RBBS_BREAK; 02140 REBAR_GetBand(infoPtr, 0)->fStyle |= RBBS_BREAK; 02141 infoPtr->iGrabbedBand = DPA_InsertPtr( 02142 infoPtr->bands, 0, hitBand); 02143 } 02144 else if(yOff > REBAR_GetBand(infoPtr, infoPtr->uNumBands - 1)->rcBand.bottom) 02145 { 02146 /* Place the band below the current bottom row */ 02147 DPA_DeletePtr(infoPtr->bands, iHitBand); 02148 hitBand->fStyle |= RBBS_BREAK; 02149 infoPtr->iGrabbedBand = DPA_InsertPtr( 02150 infoPtr->bands, infoPtr->uNumBands - 1, hitBand); 02151 } 02152 else 02153 { 02154 /* Place the band in the prexisting row the mouse is hovering over */ 02155 iRowBegin = first_visible(infoPtr); 02156 while(iRowBegin < infoPtr->uNumBands) 02157 { 02158 iNextRowBegin = get_row_end_for_band(infoPtr, iRowBegin); 02159 rowBeginBand = REBAR_GetBand(infoPtr, iRowBegin); 02160 if(rowBeginBand->rcBand.bottom > yOff) 02161 { 02162 REBAR_MoveBandToRowOffset( 02163 infoPtr, iHitBand, iRowBegin, iNextRowBegin, 02164 ((infoPtr->dwStyle & CCS_VERT) ? ptsmove->y : ptsmove->x) 02165 - REBAR_PRE_GRIPPER - infoPtr->ihitoffset, FALSE); 02166 break; 02167 } 02168 02169 iRowBegin = iNextRowBegin; 02170 } 02171 } 02172 02173 REBAR_Layout(infoPtr); 02174 } 02175 02176 02177 /* << REBAR_BeginDrag >> */ 02178 02179 02180 static LRESULT 02181 REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam) 02182 { 02183 UINT uBand = (UINT)wParam; 02184 REBAR_BAND *lpBand; 02185 02186 if (uBand >= infoPtr->uNumBands) 02187 return FALSE; 02188 02189 TRACE("deleting band %u!\n", uBand); 02190 lpBand = REBAR_GetBand(infoPtr, uBand); 02191 REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND); 02192 /* TODO: a return of 1 should probably cancel the deletion */ 02193 02194 if (lpBand->hwndChild) 02195 ShowWindow(lpBand->hwndChild, SW_HIDE); 02196 Free(lpBand->lpText); 02197 Free(lpBand); 02198 02199 infoPtr->uNumBands--; 02200 DPA_DeletePtr(infoPtr->bands, uBand); 02201 02202 REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND); 02203 02204 /* if only 1 band left the re-validate to possible eliminate gripper */ 02205 if (infoPtr->uNumBands == 1) 02206 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0)); 02207 02208 REBAR_Layout(infoPtr); 02209 02210 return TRUE; 02211 } 02212 02213 02214 /* << REBAR_DragMove >> */ 02215 /* << REBAR_EndDrag >> */ 02216 02217 02218 static LRESULT 02219 REBAR_GetBandBorders (const REBAR_INFO *infoPtr, UINT uBand, RECT *lpRect) 02220 { 02221 REBAR_BAND *lpBand; 02222 02223 if (!lpRect) 02224 return 0; 02225 if (uBand >= infoPtr->uNumBands) 02226 return 0; 02227 02228 lpBand = REBAR_GetBand(infoPtr, uBand); 02229 02230 /* FIXME - the following values were determined by experimentation */ 02231 /* with the REBAR Control Spy. I have guesses as to what the 4 and */ 02232 /* 1 are, but I am not sure. There doesn't seem to be any actual */ 02233 /* difference in size of the control area with and without the */ 02234 /* style. - GA */ 02235 if (infoPtr->dwStyle & RBS_BANDBORDERS) { 02236 if (infoPtr->dwStyle & CCS_VERT) { 02237 lpRect->left = 1; 02238 lpRect->top = lpBand->cxHeader + 4; 02239 lpRect->right = 1; 02240 lpRect->bottom = 0; 02241 } 02242 else { 02243 lpRect->left = lpBand->cxHeader + 4; 02244 lpRect->top = 1; 02245 lpRect->right = 0; 02246 lpRect->bottom = 1; 02247 } 02248 } 02249 else { 02250 lpRect->left = lpBand->cxHeader; 02251 } 02252 return 0; 02253 } 02254 02255 02256 static inline LRESULT 02257 REBAR_GetBandCount (const REBAR_INFO *infoPtr) 02258 { 02259 TRACE("band count %u!\n", infoPtr->uNumBands); 02260 02261 return infoPtr->uNumBands; 02262 } 02263 02264 02265 static LRESULT 02266 REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, UINT uIndex, LPREBARBANDINFOW lprbbi, BOOL bUnicode) 02267 { 02268 REBAR_BAND *lpBand; 02269 02270 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 02271 return FALSE; 02272 02273 if (uIndex >= infoPtr->uNumBands) 02274 return FALSE; 02275 02276 TRACE("index %u (bUnicode=%d)\n", uIndex, bUnicode); 02277 02278 /* copy band information */ 02279 lpBand = REBAR_GetBand(infoPtr, uIndex); 02280 02281 if (lprbbi->fMask & RBBIM_STYLE) 02282 lprbbi->fStyle = lpBand->fStyle; 02283 02284 if (lprbbi->fMask & RBBIM_COLORS) { 02285 lprbbi->clrFore = lpBand->clrFore; 02286 lprbbi->clrBack = lpBand->clrBack; 02287 if (lprbbi->clrBack == CLR_DEFAULT) 02288 lprbbi->clrBack = infoPtr->clrBtnFace; 02289 } 02290 02291 if (lprbbi->fMask & RBBIM_TEXT) { 02292 if (bUnicode) 02293 Str_GetPtrW(lpBand->lpText, lprbbi->lpText, lprbbi->cch); 02294 else 02295 Str_GetPtrWtoA(lpBand->lpText, (LPSTR)lprbbi->lpText, lprbbi->cch); 02296 } 02297 02298 if (lprbbi->fMask & RBBIM_IMAGE) 02299 lprbbi->iImage = lpBand->iImage; 02300 02301 if (lprbbi->fMask & RBBIM_CHILD) 02302 lprbbi->hwndChild = lpBand->hwndChild; 02303 02304 if (lprbbi->fMask & RBBIM_CHILDSIZE) { 02305 lprbbi->cxMinChild = lpBand->cxMinChild; 02306 lprbbi->cyMinChild = lpBand->cyMinChild; 02307 /* to make tests pass we follow Windows behaviour and allow to read these fields only 02308 * for RBBS_VARIABLEHEIGHTS bands */ 02309 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 02310 lprbbi->cyChild = lpBand->cyChild; 02311 lprbbi->cyMaxChild = lpBand->cyMaxChild; 02312 lprbbi->cyIntegral = lpBand->cyIntegral; 02313 } 02314 } 02315 02316 if (lprbbi->fMask & RBBIM_SIZE) 02317 lprbbi->cx = lpBand->cx; 02318 02319 if (lprbbi->fMask & RBBIM_BACKGROUND) 02320 lprbbi->hbmBack = lpBand->hbmBack; 02321 02322 if (lprbbi->fMask & RBBIM_ID) 02323 lprbbi->wID = lpBand->wID; 02324 02325 /* check for additional data */ 02326 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE) { 02327 if (lprbbi->fMask & RBBIM_IDEALSIZE) 02328 lprbbi->cxIdeal = lpBand->cxIdeal; 02329 02330 if (lprbbi->fMask & RBBIM_LPARAM) 02331 lprbbi->lParam = lpBand->lParam; 02332 02333 if (lprbbi->fMask & RBBIM_HEADERSIZE) 02334 lprbbi->cxHeader = lpBand->cxHeader; 02335 } 02336 02337 REBAR_DumpBandInfo(lprbbi); 02338 02339 return TRUE; 02340 } 02341 02342 02343 static LRESULT 02344 REBAR_GetBarHeight (const REBAR_INFO *infoPtr) 02345 { 02346 INT nHeight; 02347 02348 nHeight = infoPtr->calcSize.cy; 02349 02350 TRACE("height = %d\n", nHeight); 02351 02352 return nHeight; 02353 } 02354 02355 02356 static LRESULT 02357 REBAR_GetBarInfo (const REBAR_INFO *infoPtr, LPREBARINFO lpInfo) 02358 { 02359 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO)) 02360 return FALSE; 02361 02362 TRACE("getting bar info!\n"); 02363 02364 if (infoPtr->himl) { 02365 lpInfo->himl = infoPtr->himl; 02366 lpInfo->fMask |= RBIM_IMAGELIST; 02367 } 02368 02369 return TRUE; 02370 } 02371 02372 02373 static inline LRESULT 02374 REBAR_GetBkColor (const REBAR_INFO *infoPtr) 02375 { 02376 COLORREF clr = infoPtr->clrBk; 02377 02378 if (clr == CLR_DEFAULT) 02379 clr = infoPtr->clrBtnFace; 02380 02381 TRACE("background color 0x%06x!\n", clr); 02382 02383 return clr; 02384 } 02385 02386 02387 /* << REBAR_GetColorScheme >> */ 02388 /* << REBAR_GetDropTarget >> */ 02389 02390 02391 static LRESULT 02392 REBAR_GetPalette (const REBAR_INFO *infoPtr) 02393 { 02394 FIXME("empty stub!\n"); 02395 02396 return 0; 02397 } 02398 02399 02400 static LRESULT 02401 REBAR_GetRect (const REBAR_INFO *infoPtr, INT iBand, RECT *lprc) 02402 { 02403 REBAR_BAND *lpBand; 02404 02405 if (iBand < 0 || iBand >= infoPtr->uNumBands) 02406 return FALSE; 02407 if (!lprc) 02408 return FALSE; 02409 02410 lpBand = REBAR_GetBand(infoPtr, iBand); 02411 /* For CCS_VERT the coordinates will be swapped - like on Windows */ 02412 CopyRect (lprc, &lpBand->rcBand); 02413 02414 TRACE("band %d, (%s)\n", iBand, wine_dbgstr_rect(lprc)); 02415 02416 return TRUE; 02417 } 02418 02419 02420 static inline LRESULT 02421 REBAR_GetRowCount (const REBAR_INFO *infoPtr) 02422 { 02423 TRACE("%u\n", infoPtr->uNumRows); 02424 02425 return infoPtr->uNumRows; 02426 } 02427 02428 02429 static LRESULT 02430 REBAR_GetRowHeight (const REBAR_INFO *infoPtr, INT iRow) 02431 { 02432 int j = 0, ret = 0; 02433 UINT i; 02434 REBAR_BAND *lpBand; 02435 02436 for (i=0; i<infoPtr->uNumBands; i++) { 02437 lpBand = REBAR_GetBand(infoPtr, i); 02438 if (HIDDENBAND(lpBand)) continue; 02439 if (lpBand->iRow != iRow) continue; 02440 j = lpBand->rcBand.bottom - lpBand->rcBand.top; 02441 if (j > ret) ret = j; 02442 } 02443 02444 TRACE("row %d, height %d\n", iRow, ret); 02445 02446 return ret; 02447 } 02448 02449 02450 static inline LRESULT 02451 REBAR_GetTextColor (const REBAR_INFO *infoPtr) 02452 { 02453 TRACE("text color 0x%06x!\n", infoPtr->clrText); 02454 02455 return infoPtr->clrText; 02456 } 02457 02458 02459 static inline LRESULT 02460 REBAR_GetToolTips (const REBAR_INFO *infoPtr) 02461 { 02462 return (LRESULT)infoPtr->hwndToolTip; 02463 } 02464 02465 02466 static inline LRESULT 02467 REBAR_GetUnicodeFormat (const REBAR_INFO *infoPtr) 02468 { 02469 TRACE("%s hwnd=%p\n", 02470 infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); 02471 02472 return infoPtr->bUnicode; 02473 } 02474 02475 02476 static inline LRESULT 02477 REBAR_GetVersion (const REBAR_INFO *infoPtr) 02478 { 02479 TRACE("version %d\n", infoPtr->iVersion); 02480 return infoPtr->iVersion; 02481 } 02482 02483 02484 static LRESULT 02485 REBAR_HitTest (const REBAR_INFO *infoPtr, LPRBHITTESTINFO lprbht) 02486 { 02487 if (!lprbht) 02488 return -1; 02489 02490 REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand); 02491 02492 return lprbht->iBand; 02493 } 02494 02495 02496 static LRESULT 02497 REBAR_IdToIndex (const REBAR_INFO *infoPtr, UINT uId) 02498 { 02499 UINT i; 02500 02501 if (infoPtr->uNumBands < 1) 02502 return -1; 02503 02504 for (i = 0; i < infoPtr->uNumBands; i++) { 02505 if (REBAR_GetBand(infoPtr, i)->wID == uId) { 02506 TRACE("id %u is band %u found!\n", uId, i); 02507 return i; 02508 } 02509 } 02510 02511 TRACE("id %u is not found\n", uId); 02512 return -1; 02513 } 02514 02515 02516 static LRESULT 02517 REBAR_InsertBandT(REBAR_INFO *infoPtr, INT iIndex, const REBARBANDINFOW *lprbbi, BOOL bUnicode) 02518 { 02519 REBAR_BAND *lpBand; 02520 02521 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 02522 return FALSE; 02523 02524 /* trace the index as signed to see the -1 */ 02525 TRACE("insert band at %d (bUnicode=%d)!\n", iIndex, bUnicode); 02526 REBAR_DumpBandInfo(lprbbi); 02527 02528 if (!(lpBand = Alloc(sizeof(REBAR_BAND)))) return FALSE; 02529 if ((iIndex == -1) || (iIndex > infoPtr->uNumBands)) 02530 iIndex = infoPtr->uNumBands; 02531 if (DPA_InsertPtr(infoPtr->bands, iIndex, lpBand) == -1) 02532 { 02533 Free(lpBand); 02534 return FALSE; 02535 } 02536 infoPtr->uNumBands++; 02537 02538 TRACE("index %d!\n", iIndex); 02539 02540 /* initialize band */ 02541 memset(lpBand, 0, sizeof(*lpBand)); 02542 lpBand->clrFore = infoPtr->clrText; 02543 lpBand->clrBack = infoPtr->clrBk; 02544 lpBand->iImage = -1; 02545 02546 REBAR_CommonSetupBand(infoPtr->hwndSelf, lprbbi, lpBand); 02547 02548 /* Make sure the defaults for these are correct */ 02549 if (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE || !(lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 02550 lpBand->cyChild = lpBand->cyMinChild; 02551 lpBand->cyMaxChild = 0x7fffffff; 02552 lpBand->cyIntegral = 0; 02553 } 02554 02555 if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { 02556 if (bUnicode) 02557 Str_SetPtrW(&lpBand->lpText, lprbbi->lpText); 02558 else 02559 Str_SetPtrAtoW(&lpBand->lpText, (LPSTR)lprbbi->lpText); 02560 } 02561 02562 REBAR_ValidateBand (infoPtr, lpBand); 02563 /* On insert of second band, revalidate band 1 to possible add gripper */ 02564 if (infoPtr->uNumBands == 2) 02565 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0)); 02566 02567 REBAR_DumpBand (infoPtr); 02568 02569 REBAR_Layout(infoPtr); 02570 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 02571 02572 return TRUE; 02573 } 02574 02575 02576 static LRESULT 02577 REBAR_MaximizeBand (const REBAR_INFO *infoPtr, INT iBand, LPARAM lParam) 02578 { 02579 REBAR_BAND *lpBand; 02580 int iRowBegin, iRowEnd; 02581 int cxDesired, extra, extraOrig; 02582 int cxIdealBand; 02583 02584 /* Validate */ 02585 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) { 02586 /* error !!! */ 02587 ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n", 02588 iBand, infoPtr->uNumBands); 02589 return FALSE; 02590 } 02591 02592 lpBand = REBAR_GetBand(infoPtr, iBand); 02593 02594 if (lpBand->fStyle & RBBS_HIDDEN) 02595 { 02596 /* Windows is buggy and creates a hole */ 02597 WARN("Ignoring maximize request on a hidden band (%d)\n", iBand); 02598 return FALSE; 02599 } 02600 02601 cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD; 02602 if (lParam && (lpBand->cxEffective < cxIdealBand)) 02603 cxDesired = cxIdealBand; 02604 else 02605 cxDesired = infoPtr->calcSize.cx; 02606 02607 iRowBegin = get_row_begin_for_band(infoPtr, iBand); 02608 iRowEnd = get_row_end_for_band(infoPtr, iBand); 02609 extraOrig = extra = cxDesired - lpBand->cxEffective; 02610 if (extra > 0) 02611 extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iBand, extra, TRUE); 02612 if (extra > 0) 02613 extra = REBAR_ShrinkBandsLTR(infoPtr, next_visible(infoPtr, iBand), iRowEnd, extra, TRUE); 02614 lpBand->cxEffective += extraOrig - extra; 02615 lpBand->cx = lpBand->cxEffective; 02616 TRACE("(%d, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", iBand, lParam, cxDesired, lpBand->cx, extraOrig, extra); 02617 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 02618 02619 if (infoPtr->dwStyle & CCS_VERT) 02620 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd); 02621 else 02622 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd); 02623 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 02624 return TRUE; 02625 02626 } 02627 02628 02629 static LRESULT 02630 REBAR_MinimizeBand (const REBAR_INFO *infoPtr, INT iBand) 02631 { 02632 REBAR_BAND *lpBand; 02633 int iPrev, iRowBegin, iRowEnd; 02634 02635 /* A "minimize" band is equivalent to "dragging" the gripper 02636 * of than band to the right till the band is only the size 02637 * of the cxHeader. 02638 */ 02639 02640 /* Validate */ 02641 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) { 02642 /* error !!! */ 02643 ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n", 02644 iBand, infoPtr->uNumBands); 02645 return FALSE; 02646 } 02647 02648 /* compute amount of movement and validate */ 02649 lpBand = REBAR_GetBand(infoPtr, iBand); 02650 02651 if (lpBand->fStyle & RBBS_HIDDEN) 02652 { 02653 /* Windows is buggy and creates a hole/overlap */ 02654 WARN("Ignoring minimize request on a hidden band (%d)\n", iBand); 02655 return FALSE; 02656 } 02657 02658 iPrev = prev_visible(infoPtr, iBand); 02659 /* if first band in row */ 02660 if (iPrev < 0 || REBAR_GetBand(infoPtr, iPrev)->iRow != lpBand->iRow) { 02661 int iNext = next_visible(infoPtr, iBand); 02662 if (iNext < infoPtr->uNumBands && REBAR_GetBand(infoPtr, iNext)->iRow == lpBand->iRow) { 02663 TRACE("(%d): Minimizing the first band in row is by maximizing the second\n", iBand); 02664 REBAR_MaximizeBand(infoPtr, iNext, FALSE); 02665 } 02666 else 02667 TRACE("(%d): Only one band in row - nothing to do\n", iBand); 02668 return TRUE; 02669 } 02670 02671 REBAR_GetBand(infoPtr, iPrev)->cxEffective += lpBand->cxEffective - lpBand->cxMinBand; 02672 REBAR_GetBand(infoPtr, iPrev)->cx = REBAR_GetBand(infoPtr, iPrev)->cxEffective; 02673 lpBand->cx = lpBand->cxEffective = lpBand->cxMinBand; 02674 02675 iRowBegin = get_row_begin_for_band(infoPtr, iBand); 02676 iRowEnd = get_row_end_for_band(infoPtr, iBand); 02677 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 02678 02679 if (infoPtr->dwStyle & CCS_VERT) 02680 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd); 02681 else 02682 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd); 02683 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 02684 return FALSE; 02685 } 02686 02687 02688 static LRESULT 02689 REBAR_MoveBand (REBAR_INFO *infoPtr, INT iFrom, INT iTo) 02690 { 02691 REBAR_BAND *lpBand; 02692 02693 /* Validate */ 02694 if ((infoPtr->uNumBands == 0) || 02695 (iFrom < 0) || iFrom >= infoPtr->uNumBands || 02696 (iTo < 0) || iTo >= infoPtr->uNumBands) { 02697 /* error !!! */ 02698 ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n", 02699 iFrom, iTo, infoPtr->uNumBands); 02700 return FALSE; 02701 } 02702 02703 lpBand = REBAR_GetBand(infoPtr, iFrom); 02704 DPA_DeletePtr(infoPtr->bands, iFrom); 02705 DPA_InsertPtr(infoPtr->bands, iTo, lpBand); 02706 02707 TRACE("moved band %d to index %d\n", iFrom, iTo); 02708 REBAR_DumpBand (infoPtr); 02709 02710 /* **************************************************** */ 02711 /* */ 02712 /* We do not do a REBAR_Layout here because the native */ 02713 /* control does not do that. The actual layout and */ 02714 /* repaint is done by the *next* real action, ex.: */ 02715 /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc. */ 02716 /* */ 02717 /* **************************************************** */ 02718 02719 return TRUE; 02720 } 02721 02722 02723 /* return TRUE if two strings are different */ 02724 static BOOL 02725 REBAR_strdifW( LPCWSTR a, LPCWSTR b ) 02726 { 02727 return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) ); 02728 } 02729 02730 static LRESULT 02731 REBAR_SetBandInfoT(REBAR_INFO *infoPtr, INT iBand, const REBARBANDINFOW *lprbbi, BOOL bUnicode) 02732 { 02733 REBAR_BAND *lpBand; 02734 UINT uChanged; 02735 02736 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 02737 return FALSE; 02738 02739 if (iBand >= infoPtr->uNumBands) 02740 return FALSE; 02741 02742 TRACE("index %d\n", iBand); 02743 REBAR_DumpBandInfo (lprbbi); 02744 02745 /* set band information */ 02746 lpBand = REBAR_GetBand(infoPtr, iBand); 02747 02748 uChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); 02749 if (lprbbi->fMask & RBBIM_TEXT) { 02750 LPWSTR wstr = NULL; 02751 if (bUnicode) 02752 Str_SetPtrW(&wstr, lprbbi->lpText); 02753 else 02754 Str_SetPtrAtoW(&wstr, (LPSTR)lprbbi->lpText); 02755 02756 if (REBAR_strdifW(wstr, lpBand->lpText)) { 02757 Free(lpBand->lpText); 02758 lpBand->lpText = wstr; 02759 uChanged |= RBBIM_TEXT; 02760 } 02761 else 02762 Free(wstr); 02763 } 02764 02765 REBAR_ValidateBand (infoPtr, lpBand); 02766 02767 REBAR_DumpBand (infoPtr); 02768 02769 if (uChanged & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE | RBBIM_IMAGE)) { 02770 REBAR_Layout(infoPtr); 02771 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 02772 } 02773 02774 return TRUE; 02775 } 02776 02777 02778 static LRESULT 02779 REBAR_SetBarInfo (REBAR_INFO *infoPtr, const REBARINFO *lpInfo) 02780 { 02781 REBAR_BAND *lpBand; 02782 UINT i; 02783 02784 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO)) 02785 return FALSE; 02786 02787 TRACE("setting bar info!\n"); 02788 02789 if (lpInfo->fMask & RBIM_IMAGELIST) { 02790 infoPtr->himl = lpInfo->himl; 02791 if (infoPtr->himl) { 02792 INT cx, cy; 02793 ImageList_GetIconSize (infoPtr->himl, &cx, &cy); 02794 infoPtr->imageSize.cx = cx; 02795 infoPtr->imageSize.cy = cy; 02796 } 02797 else { 02798 infoPtr->imageSize.cx = 0; 02799 infoPtr->imageSize.cy = 0; 02800 } 02801 TRACE("new image cx=%d, cy=%d\n", infoPtr->imageSize.cx, 02802 infoPtr->imageSize.cy); 02803 } 02804 02805 /* revalidate all bands to reset flags for images in headers of bands */ 02806 for (i=0; i<infoPtr->uNumBands; i++) { 02807 lpBand = REBAR_GetBand(infoPtr, i); 02808 REBAR_ValidateBand (infoPtr, lpBand); 02809 } 02810 02811 return TRUE; 02812 } 02813 02814 02815 static LRESULT 02816 REBAR_SetBkColor (REBAR_INFO *infoPtr, COLORREF clr) 02817 { 02818 COLORREF clrTemp; 02819 02820 clrTemp = infoPtr->clrBk; 02821 infoPtr->clrBk = clr; 02822 02823 TRACE("background color 0x%06x!\n", infoPtr->clrBk); 02824 02825 return clrTemp; 02826 } 02827 02828 02829 /* << REBAR_SetColorScheme >> */ 02830 /* << REBAR_SetPalette >> */ 02831 02832 02833 static LRESULT 02834 REBAR_SetParent (REBAR_INFO *infoPtr, HWND parent) 02835 { 02836 HWND hwndTemp = infoPtr->hwndNotify; 02837 02838 infoPtr->hwndNotify = parent; 02839 02840 return (LRESULT)hwndTemp; 02841 } 02842 02843 02844 static LRESULT 02845 REBAR_SetTextColor (REBAR_INFO *infoPtr, COLORREF clr) 02846 { 02847 COLORREF clrTemp; 02848 02849 clrTemp = infoPtr->clrText; 02850 infoPtr->clrText = clr; 02851 02852 TRACE("text color 0x%06x!\n", infoPtr->clrText); 02853 02854 return clrTemp; 02855 } 02856 02857 02858 /* << REBAR_SetTooltips >> */ 02859 02860 02861 static inline LRESULT 02862 REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, BOOL unicode) 02863 { 02864 BOOL bTemp = infoPtr->bUnicode; 02865 02866 TRACE("to %s hwnd=%p, was %s\n", 02867 unicode ? "TRUE" : "FALSE", infoPtr->hwndSelf, 02868 (bTemp) ? "TRUE" : "FALSE"); 02869 02870 infoPtr->bUnicode = unicode; 02871 02872 return bTemp; 02873 } 02874 02875 02876 static LRESULT 02877 REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion) 02878 { 02879 INT iOldVersion = infoPtr->iVersion; 02880 02881 if (iVersion > COMCTL32_VERSION) 02882 return -1; 02883 02884 infoPtr->iVersion = iVersion; 02885 02886 TRACE("new version %d\n", iVersion); 02887 02888 return iOldVersion; 02889 } 02890 02891 02892 static LRESULT 02893 REBAR_ShowBand (REBAR_INFO *infoPtr, INT iBand, BOOL show) 02894 { 02895 REBAR_BAND *lpBand; 02896 02897 if (iBand < 0 || iBand >= infoPtr->uNumBands) 02898 return FALSE; 02899 02900 lpBand = REBAR_GetBand(infoPtr, iBand); 02901 02902 if (show) { 02903 TRACE("show band %d\n", iBand); 02904 lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN; 02905 if (IsWindow (lpBand->hwndChild)) 02906 ShowWindow (lpBand->hwndChild, SW_SHOW); 02907 } 02908 else { 02909 TRACE("hide band %d\n", iBand); 02910 lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN; 02911 if (IsWindow (lpBand->hwndChild)) 02912 ShowWindow (lpBand->hwndChild, SW_HIDE); 02913 } 02914 02915 REBAR_Layout(infoPtr); 02916 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 02917 02918 return TRUE; 02919 } 02920 02921 02922 static LRESULT 02923 REBAR_SizeToRect (REBAR_INFO *infoPtr, const RECT *lpRect) 02924 { 02925 if (!lpRect) return FALSE; 02926 02927 TRACE("[%s]\n", wine_dbgstr_rect(lpRect)); 02928 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect)); 02929 return TRUE; 02930 } 02931 02932 02933 02934 static LRESULT 02935 REBAR_Create (REBAR_INFO *infoPtr, LPCREATESTRUCTW cs) 02936 { 02937 RECT wnrc1, clrc1; 02938 02939 if (TRACE_ON(rebar)) { 02940 GetWindowRect(infoPtr->hwndSelf, &wnrc1); 02941 GetClientRect(infoPtr->hwndSelf, &clrc1); 02942 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n", 02943 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1), 02944 cs->x, cs->y, cs->cx, cs->cy); 02945 } 02946 02947 TRACE("created!\n"); 02948 02949 if (OpenThemeData (infoPtr->hwndSelf, themeClass)) 02950 { 02951 /* native seems to clear WS_BORDER when themed */ 02952 infoPtr->dwStyle &= ~WS_BORDER; 02953 } 02954 02955 return 0; 02956 } 02957 02958 02959 static LRESULT 02960 REBAR_Destroy (REBAR_INFO *infoPtr) 02961 { 02962 REBAR_BAND *lpBand; 02963 UINT i; 02964 02965 /* clean up each band */ 02966 for (i = 0; i < infoPtr->uNumBands; i++) { 02967 lpBand = REBAR_GetBand(infoPtr, i); 02968 02969 /* delete text strings */ 02970 Free (lpBand->lpText); 02971 lpBand->lpText = NULL; 02972 /* destroy child window */ 02973 DestroyWindow (lpBand->hwndChild); 02974 Free (lpBand); 02975 } 02976 02977 /* free band array */ 02978 DPA_Destroy (infoPtr->bands); 02979 infoPtr->bands = NULL; 02980 02981 DestroyCursor (infoPtr->hcurArrow); 02982 DestroyCursor (infoPtr->hcurHorz); 02983 DestroyCursor (infoPtr->hcurVert); 02984 DestroyCursor (infoPtr->hcurDrag); 02985 if (infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont); 02986 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); 02987 02988 CloseThemeData (GetWindowTheme (infoPtr->hwndSelf)); 02989 02990 /* free rebar info data */ 02991 Free (infoPtr); 02992 TRACE("destroyed!\n"); 02993 return 0; 02994 } 02995 02996 static LRESULT 02997 REBAR_GetFont (const REBAR_INFO *infoPtr) 02998 { 02999 return (LRESULT)infoPtr->hFont; 03000 } 03001 03002 static LRESULT 03003 REBAR_PushChevron(const REBAR_INFO *infoPtr, UINT uBand, LPARAM lParam) 03004 { 03005 if (uBand < infoPtr->uNumBands) 03006 { 03007 NMREBARCHEVRON nmrbc; 03008 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand); 03009 03010 TRACE("Pressed chevron on band %u\n", uBand); 03011 03012 /* redraw chevron in pushed state */ 03013 lpBand->fDraw |= DRAW_CHEVRONPUSHED; 03014 RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0, 03015 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); 03016 03017 /* notify app so it can display a popup menu or whatever */ 03018 nmrbc.uBand = uBand; 03019 nmrbc.wID = lpBand->wID; 03020 nmrbc.lParam = lpBand->lParam; 03021 nmrbc.rc = lpBand->rcChevron; 03022 nmrbc.lParamNM = lParam; 03023 REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED); 03024 03025 /* redraw chevron in previous state */ 03026 lpBand->fDraw &= ~DRAW_CHEVRONPUSHED; 03027 InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE); 03028 03029 return TRUE; 03030 } 03031 return FALSE; 03032 } 03033 03034 static LRESULT 03035 REBAR_LButtonDown (REBAR_INFO *infoPtr, LPARAM lParam) 03036 { 03037 UINT htFlags; 03038 INT iHitBand; 03039 POINT ptMouseDown; 03040 ptMouseDown.x = (short)LOWORD(lParam); 03041 ptMouseDown.y = (short)HIWORD(lParam); 03042 03043 REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand); 03044 03045 if (htFlags == RBHT_CHEVRON) 03046 { 03047 REBAR_PushChevron(infoPtr, iHitBand, 0); 03048 } 03049 else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION) 03050 { 03051 REBAR_BAND *lpBand; 03052 03053 TRACE("Starting drag\n"); 03054 03055 lpBand = REBAR_GetBand(infoPtr, iHitBand); 03056 03057 SetCapture (infoPtr->hwndSelf); 03058 infoPtr->iGrabbedBand = iHitBand; 03059 03060 /* save off the LOWORD and HIWORD of lParam as initial x,y */ 03061 infoPtr->dragStart.x = (short)LOWORD(lParam); 03062 infoPtr->dragStart.y = (short)HIWORD(lParam); 03063 infoPtr->dragNow = infoPtr->dragStart; 03064 if (infoPtr->dwStyle & CCS_VERT) 03065 infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER); 03066 else 03067 infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER); 03068 } 03069 return 0; 03070 } 03071 03072 static LRESULT 03073 REBAR_LButtonUp (REBAR_INFO *infoPtr) 03074 { 03075 if (infoPtr->iGrabbedBand >= 0) 03076 { 03077 NMHDR layout; 03078 RECT rect; 03079 03080 infoPtr->dragStart.x = 0; 03081 infoPtr->dragStart.y = 0; 03082 infoPtr->dragNow = infoPtr->dragStart; 03083 03084 ReleaseCapture (); 03085 03086 if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) { 03087 REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED); 03088 REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG); 03089 infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED; 03090 } 03091 03092 infoPtr->iGrabbedBand = -1; 03093 03094 GetClientRect(infoPtr->hwndSelf, &rect); 03095 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 03096 } 03097 03098 return 0; 03099 } 03100 03101 static LRESULT 03102 REBAR_MouseLeave (REBAR_INFO *infoPtr) 03103 { 03104 if (infoPtr->ichevronhotBand >= 0) 03105 { 03106 REBAR_BAND *lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand); 03107 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) 03108 { 03109 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; 03110 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 03111 } 03112 } 03113 infoPtr->iOldBand = -1; 03114 infoPtr->ichevronhotBand = -2; 03115 03116 return TRUE; 03117 } 03118 03119 static LRESULT 03120 REBAR_MouseMove (REBAR_INFO *infoPtr, LPARAM lParam) 03121 { 03122 REBAR_BAND *lpChevronBand; 03123 POINT ptMove; 03124 03125 ptMove.x = (short)LOWORD(lParam); 03126 ptMove.y = (short)HIWORD(lParam); 03127 03128 /* if we are currently dragging a band */ 03129 if (infoPtr->iGrabbedBand >= 0) 03130 { 03131 REBAR_BAND *band; 03132 int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y); 03133 03134 if (GetCapture() != infoPtr->hwndSelf) 03135 ERR("We are dragging but haven't got capture?!?\n"); 03136 03137 band = REBAR_GetBand(infoPtr, infoPtr->iGrabbedBand); 03138 03139 /* if mouse did not move much, exit */ 03140 if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) && 03141 (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0; 03142 03143 /* on first significant mouse movement, issue notify */ 03144 if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) { 03145 if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) { 03146 /* Notify returned TRUE - abort drag */ 03147 infoPtr->dragStart.x = 0; 03148 infoPtr->dragStart.y = 0; 03149 infoPtr->dragNow = infoPtr->dragStart; 03150 infoPtr->iGrabbedBand = -1; 03151 ReleaseCapture (); 03152 return 0; 03153 } 03154 infoPtr->fStatus |= BEGIN_DRAG_ISSUED; 03155 } 03156 03157 /* Test for valid drag case - must not be first band in row */ 03158 if ((yPtMove < band->rcBand.top) || 03159 (yPtMove > band->rcBand.bottom)) { 03160 REBAR_HandleUDDrag (infoPtr, &ptMove); 03161 } 03162 else { 03163 REBAR_HandleLRDrag (infoPtr, &ptMove); 03164 } 03165 } 03166 else 03167 { 03168 INT iHitBand; 03169 UINT htFlags; 03170 TRACKMOUSEEVENT trackinfo; 03171 03172 REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand); 03173 03174 if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand) 03175 { 03176 lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand); 03177 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) 03178 { 03179 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; 03180 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 03181 } 03182 infoPtr->ichevronhotBand = -2; 03183 } 03184 03185 if (htFlags == RBHT_CHEVRON) 03186 { 03187 /* fill in the TRACKMOUSEEVENT struct */ 03188 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); 03189 trackinfo.dwFlags = TME_QUERY; 03190 trackinfo.hwndTrack = infoPtr->hwndSelf; 03191 trackinfo.dwHoverTime = 0; 03192 03193 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ 03194 _TrackMouseEvent(&trackinfo); 03195 03196 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ 03197 if(!(trackinfo.dwFlags & TME_LEAVE)) 03198 { 03199 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ 03200 03201 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ 03202 /* and can properly deactivate the hot chevron */ 03203 _TrackMouseEvent(&trackinfo); 03204 } 03205 03206 lpChevronBand = REBAR_GetBand(infoPtr, iHitBand); 03207 if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT)) 03208 { 03209 lpChevronBand->fDraw |= DRAW_CHEVRONHOT; 03210 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 03211 infoPtr->ichevronhotBand = iHitBand; 03212 } 03213 } 03214 infoPtr->iOldBand = iHitBand; 03215 } 03216 03217 return 0; 03218 } 03219 03220 03221 static inline LRESULT 03222 REBAR_NCCalcSize (const REBAR_INFO *infoPtr, RECT *rect) 03223 { 03224 HTHEME theme; 03225 03226 if (infoPtr->dwStyle & WS_BORDER) { 03227 rect->left = min(rect->left + GetSystemMetrics(SM_CXEDGE), rect->right); 03228 rect->right = max(rect->right - GetSystemMetrics(SM_CXEDGE), rect->left); 03229 rect->top = min(rect->top + GetSystemMetrics(SM_CYEDGE), rect->bottom); 03230 rect->bottom = max(rect->bottom - GetSystemMetrics(SM_CYEDGE), rect->top); 03231 } 03232 else if ((theme = GetWindowTheme (infoPtr->hwndSelf))) 03233 { 03234 /* FIXME: should use GetThemeInt */ 03235 rect->top = min(rect->top + 1, rect->bottom); 03236 } 03237 TRACE("new client=(%s)\n", wine_dbgstr_rect(rect)); 03238 return 0; 03239 } 03240 03241 03242 static LRESULT 03243 REBAR_NCCreate (HWND hwnd, const CREATESTRUCTW *cs) 03244 { 03245 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); 03246 RECT wnrc1, clrc1; 03247 NONCLIENTMETRICSW ncm; 03248 HFONT tfont; 03249 03250 if (infoPtr) { 03251 ERR("Strange info structure pointer *not* NULL\n"); 03252 return FALSE; 03253 } 03254 03255 if (TRACE_ON(rebar)) { 03256 GetWindowRect(hwnd, &wnrc1); 03257 GetClientRect(hwnd, &clrc1); 03258 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n", 03259 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1), 03260 cs->x, cs->y, cs->cx, cs->cy); 03261 } 03262 03263 /* allocate memory for info structure */ 03264 infoPtr = Alloc (sizeof(REBAR_INFO)); 03265 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 03266 03267 /* initialize info structure - initial values are 0 */ 03268 infoPtr->clrBk = CLR_NONE; 03269 infoPtr->clrText = CLR_NONE; 03270 infoPtr->clrBtnText = comctl32_color.clrBtnText; 03271 infoPtr->clrBtnFace = comctl32_color.clrBtnFace; 03272 infoPtr->iOldBand = -1; 03273 infoPtr->ichevronhotBand = -2; 03274 infoPtr->iGrabbedBand = -1; 03275 infoPtr->hwndSelf = hwnd; 03276 infoPtr->DoRedraw = TRUE; 03277 infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); 03278 infoPtr->hcurHorz = LoadCursorW (0, (LPWSTR)IDC_SIZEWE); 03279 infoPtr->hcurVert = LoadCursorW (0, (LPWSTR)IDC_SIZENS); 03280 infoPtr->hcurDrag = LoadCursorW (0, (LPWSTR)IDC_SIZE); 03281 infoPtr->fStatus = 0; 03282 infoPtr->hFont = GetStockObject (SYSTEM_FONT); 03283 infoPtr->bands = DPA_Create(8); 03284 03285 /* issue WM_NOTIFYFORMAT to get unicode status of parent */ 03286 REBAR_NotifyFormat(infoPtr, NF_REQUERY); 03287 03288 /* Stow away the original style */ 03289 infoPtr->orgStyle = cs->style; 03290 /* add necessary styles to the requested styles */ 03291 infoPtr->dwStyle = cs->style | WS_VISIBLE; 03292 if ((infoPtr->dwStyle & CCS_LAYOUT_MASK) == 0) 03293 infoPtr->dwStyle |= CCS_TOP; 03294 SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle); 03295 03296 /* get font handle for Caption Font */ 03297 ncm.cbSize = sizeof(ncm); 03298 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); 03299 /* if the font is bold, set to normal */ 03300 if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) { 03301 ncm.lfCaptionFont.lfWeight = FW_NORMAL; 03302 } 03303 tfont = CreateFontIndirectW (&ncm.lfCaptionFont); 03304 if (tfont) { 03305 infoPtr->hFont = infoPtr->hDefaultFont = tfont; 03306 } 03307 03308 /* native does: 03309 GetSysColor (numerous); 03310 GetSysColorBrush (numerous) (see WM_SYSCOLORCHANGE); 03311 *GetStockObject (SYSTEM_FONT); 03312 *SetWindowLong (hwnd, 0, info ptr); 03313 *WM_NOTIFYFORMAT; 03314 *SetWindowLong (hwnd, GWL_STYLE, style+0x10000001); 03315 WS_VISIBLE = 0x10000000; 03316 CCS_TOP = 0x00000001; 03317 *SystemParametersInfo (SPI_GETNONCLIENTMETRICS...); 03318 *CreateFontIndirect (lfCaptionFont from above); 03319 GetDC (); 03320 SelectObject (hdc, fontabove); 03321 GetTextMetrics (hdc, ); guessing is tmHeight 03322 SelectObject (hdc, oldfont); 03323 ReleaseDC (); 03324 GetWindowRect (); 03325 MapWindowPoints (0, parent, rectabove, 2); 03326 GetWindowRect (); 03327 GetClientRect (); 03328 ClientToScreen (clientrect); 03329 SetWindowPos (hwnd, 0, 0, 0, 0, 0, SWP_NOZORDER); 03330 */ 03331 return TRUE; 03332 } 03333 03334 03335 static LRESULT 03336 REBAR_NCHitTest (const REBAR_INFO *infoPtr, LPARAM lParam) 03337 { 03338 NMMOUSE nmmouse; 03339 POINT clpt; 03340 INT i; 03341 UINT scrap; 03342 LRESULT ret = HTCLIENT; 03343 03344 /* 03345 * Differences from doc at MSDN (as observed with version 4.71 of 03346 * comctl32.dll 03347 * 1. doc says nmmouse.pt is in screen coord, trace shows client coord. 03348 * 2. if band is not identified .dwItemSpec is 0xffffffff. 03349 * 3. native always seems to return HTCLIENT if notify return is 0. 03350 */ 03351 03352 clpt.x = (short)LOWORD(lParam); 03353 clpt.y = (short)HIWORD(lParam); 03354 ScreenToClient (infoPtr->hwndSelf, &clpt); 03355 REBAR_InternalHitTest (infoPtr, &clpt, &scrap, 03356 (INT *)&nmmouse.dwItemSpec); 03357 nmmouse.dwItemData = 0; 03358 nmmouse.pt = clpt; 03359 nmmouse.dwHitInfo = 0; 03360 if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) { 03361 TRACE("notify changed return value from %ld to %d\n", 03362 ret, i); 03363 ret = (LRESULT) i; 03364 } 03365 TRACE("returning %ld, client point (%d,%d)\n", ret, clpt.x, clpt.y); 03366 return ret; 03367 } 03368 03369 03370 static LRESULT 03371 REBAR_NCPaint (const REBAR_INFO *infoPtr) 03372 { 03373 RECT rcWindow; 03374 HDC hdc; 03375 HTHEME theme; 03376 03377 if (infoPtr->dwStyle & WS_MINIMIZE) 03378 return 0; /* Nothing to do */ 03379 03380 if (infoPtr->dwStyle & WS_BORDER) { 03381 03382 /* adjust rectangle and draw the necessary edge */ 03383 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) 03384 return 0; 03385 GetWindowRect (infoPtr->hwndSelf, &rcWindow); 03386 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 03387 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow)); 03388 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT); 03389 ReleaseDC( infoPtr->hwndSelf, hdc ); 03390 } 03391 else if ((theme = GetWindowTheme (infoPtr->hwndSelf))) 03392 { 03393 /* adjust rectangle and draw the necessary edge */ 03394 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) 03395 return 0; 03396 GetWindowRect (infoPtr->hwndSelf, &rcWindow); 03397 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 03398 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow)); 03399 DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL); 03400 ReleaseDC( infoPtr->hwndSelf, hdc ); 03401 } 03402 03403 return 0; 03404 } 03405 03406 03407 static LRESULT 03408 REBAR_NotifyFormat (REBAR_INFO *infoPtr, LPARAM cmd) 03409 { 03410 INT i; 03411 03412 if (cmd == NF_REQUERY) { 03413 i = SendMessageW(REBAR_GetNotifyParent (infoPtr), 03414 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); 03415 if ((i != NFR_ANSI) && (i != NFR_UNICODE)) { 03416 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); 03417 i = NFR_ANSI; 03418 } 03419 infoPtr->bUnicode = (i == NFR_UNICODE) ? 1 : 0; 03420 return (LRESULT)i; 03421 } 03422 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI); 03423 } 03424 03425 03426 static LRESULT 03427 REBAR_Paint (const REBAR_INFO *infoPtr, HDC hdc) 03428 { 03429 if (hdc) { 03430 TRACE("painting\n"); 03431 REBAR_Refresh (infoPtr, hdc); 03432 } else { 03433 PAINTSTRUCT ps; 03434 hdc = BeginPaint (infoPtr->hwndSelf, &ps); 03435 TRACE("painting (%s)\n", wine_dbgstr_rect(&ps.rcPaint)); 03436 if (ps.fErase) { 03437 /* Erase area of paint if requested */ 03438 REBAR_EraseBkGnd (infoPtr, hdc); 03439 } 03440 REBAR_Refresh (infoPtr, hdc); 03441 EndPaint (infoPtr->hwndSelf, &ps); 03442 } 03443 03444 return 0; 03445 } 03446 03447 03448 static LRESULT 03449 REBAR_SetCursor (const REBAR_INFO *infoPtr, LPARAM lParam) 03450 { 03451 POINT pt; 03452 UINT flags; 03453 03454 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); 03455 03456 GetCursorPos (&pt); 03457 ScreenToClient (infoPtr->hwndSelf, &pt); 03458 03459 REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL); 03460 03461 if (flags == RBHT_GRABBER) { 03462 if ((infoPtr->dwStyle & CCS_VERT) && 03463 !(infoPtr->dwStyle & RBS_VERTICALGRIPPER)) 03464 SetCursor (infoPtr->hcurVert); 03465 else 03466 SetCursor (infoPtr->hcurHorz); 03467 } 03468 else if (flags != RBHT_CLIENT) 03469 SetCursor (infoPtr->hcurArrow); 03470 03471 return 0; 03472 } 03473 03474 03475 static LRESULT 03476 REBAR_SetFont (REBAR_INFO *infoPtr, HFONT font) 03477 { 03478 REBAR_BAND *lpBand; 03479 UINT i; 03480 03481 infoPtr->hFont = font; 03482 03483 /* revalidate all bands to change sizes of text in headers of bands */ 03484 for (i=0; i<infoPtr->uNumBands; i++) { 03485 lpBand = REBAR_GetBand(infoPtr, i); 03486 REBAR_ValidateBand (infoPtr, lpBand); 03487 } 03488 03489 REBAR_Layout(infoPtr); 03490 return 0; 03491 } 03492 03493 03494 /***************************************************** 03495 * 03496 * Handles the WM_SETREDRAW message. 03497 * 03498 * Documentation: 03499 * According to testing V4.71 of COMCTL32 returns the 03500 * *previous* status of the redraw flag (either 0 or -1) 03501 * instead of the MSDN documented value of 0 if handled 03502 * 03503 *****************************************************/ 03504 static inline LRESULT 03505 REBAR_SetRedraw (REBAR_INFO *infoPtr, BOOL redraw) 03506 { 03507 BOOL oldredraw = infoPtr->DoRedraw; 03508 03509 TRACE("set to %s, fStatus=%08x\n", 03510 (redraw) ? "TRUE" : "FALSE", infoPtr->fStatus); 03511 infoPtr->DoRedraw = redraw; 03512 if (redraw) { 03513 if (infoPtr->fStatus & BAND_NEEDS_REDRAW) { 03514 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); 03515 REBAR_ForceResize (infoPtr); 03516 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 03517 } 03518 infoPtr->fStatus &= ~BAND_NEEDS_REDRAW; 03519 } 03520 return (oldredraw) ? -1 : 0; 03521 } 03522 03523 03524 static LRESULT 03525 REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 03526 { 03527 TRACE("wParam=%lx, lParam=%lx\n", wParam, lParam); 03528 03529 /* avoid _Layout resize recursion (but it shouldn't be infinite and it seems Windows does recurse) */ 03530 if (infoPtr->fStatus & SELF_RESIZE) { 03531 infoPtr->fStatus &= ~SELF_RESIZE; 03532 TRACE("SELF_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n", 03533 infoPtr->fStatus, lParam); 03534 return 0; 03535 } 03536 03537 if (infoPtr->dwStyle & RBS_AUTOSIZE) 03538 REBAR_AutoSize(infoPtr, TRUE); 03539 else 03540 REBAR_Layout(infoPtr); 03541 03542 return 0; 03543 } 03544 03545 03546 static LRESULT 03547 REBAR_StyleChanged (REBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle) 03548 { 03549 TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n", 03550 infoPtr->dwStyle, lpStyle->styleOld, lpStyle->styleNew); 03551 if (nType == GWL_STYLE) 03552 { 03553 infoPtr->orgStyle = infoPtr->dwStyle = lpStyle->styleNew; 03554 if (GetWindowTheme (infoPtr->hwndSelf)) 03555 infoPtr->dwStyle &= ~WS_BORDER; 03556 /* maybe it should be COMMON_STYLES like in toolbar */ 03557 if ((lpStyle->styleNew ^ lpStyle->styleOld) & CCS_VERT) 03558 REBAR_Layout(infoPtr); 03559 } 03560 return FALSE; 03561 } 03562 03563 /* update theme after a WM_THEMECHANGED message */ 03564 static LRESULT theme_changed (REBAR_INFO* infoPtr) 03565 { 03566 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 03567 CloseThemeData (theme); 03568 theme = OpenThemeData (infoPtr->hwndSelf, themeClass); 03569 /* WS_BORDER disappears when theming is enabled and reappears when 03570 * disabled... */ 03571 infoPtr->dwStyle &= ~WS_BORDER; 03572 infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER); 03573 return 0; 03574 } 03575 03576 static LRESULT 03577 REBAR_WindowPosChanged (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 03578 { 03579 LRESULT ret; 03580 RECT rc; 03581 03582 ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED, 03583 wParam, lParam); 03584 GetWindowRect(infoPtr->hwndSelf, &rc); 03585 TRACE("hwnd %p new pos (%s)\n", infoPtr->hwndSelf, wine_dbgstr_rect(&rc)); 03586 return ret; 03587 } 03588 03589 03590 static LRESULT WINAPI 03591 REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 03592 { 03593 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); 03594 03595 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", 03596 hwnd, uMsg, wParam, lParam); 03597 if (!infoPtr && (uMsg != WM_NCCREATE)) 03598 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 03599 switch (uMsg) 03600 { 03601 /* case RB_BEGINDRAG: */ 03602 03603 case RB_DELETEBAND: 03604 return REBAR_DeleteBand (infoPtr, wParam); 03605 03606 /* case RB_DRAGMOVE: */ 03607 /* case RB_ENDDRAG: */ 03608 03609 case RB_GETBANDBORDERS: 03610 return REBAR_GetBandBorders (infoPtr, wParam, (LPRECT)lParam); 03611 03612 case RB_GETBANDCOUNT: 03613 return REBAR_GetBandCount (infoPtr); 03614 03615 case RB_GETBANDINFO_OLD: 03616 case RB_GETBANDINFOA: 03617 case RB_GETBANDINFOW: 03618 return REBAR_GetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 03619 uMsg == RB_GETBANDINFOW); 03620 case RB_GETBARHEIGHT: 03621 return REBAR_GetBarHeight (infoPtr); 03622 03623 case RB_GETBARINFO: 03624 return REBAR_GetBarInfo (infoPtr, (LPREBARINFO)lParam); 03625 03626 case RB_GETBKCOLOR: 03627 return REBAR_GetBkColor (infoPtr); 03628 03629 /* case RB_GETCOLORSCHEME: */ 03630 /* case RB_GETDROPTARGET: */ 03631 03632 case RB_GETPALETTE: 03633 return REBAR_GetPalette (infoPtr); 03634 03635 case RB_GETRECT: 03636 return REBAR_GetRect (infoPtr, wParam, (LPRECT)lParam); 03637 03638 case RB_GETROWCOUNT: 03639 return REBAR_GetRowCount (infoPtr); 03640 03641 case RB_GETROWHEIGHT: 03642 return REBAR_GetRowHeight (infoPtr, wParam); 03643 03644 case RB_GETTEXTCOLOR: 03645 return REBAR_GetTextColor (infoPtr); 03646 03647 case RB_GETTOOLTIPS: 03648 return REBAR_GetToolTips (infoPtr); 03649 03650 case RB_GETUNICODEFORMAT: 03651 return REBAR_GetUnicodeFormat (infoPtr); 03652 03653 case CCM_GETVERSION: 03654 return REBAR_GetVersion (infoPtr); 03655 03656 case RB_HITTEST: 03657 return REBAR_HitTest (infoPtr, (LPRBHITTESTINFO)lParam); 03658 03659 case RB_IDTOINDEX: 03660 return REBAR_IdToIndex (infoPtr, wParam); 03661 03662 case RB_INSERTBANDA: 03663 case RB_INSERTBANDW: 03664 return REBAR_InsertBandT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 03665 uMsg == RB_INSERTBANDW); 03666 case RB_MAXIMIZEBAND: 03667 return REBAR_MaximizeBand (infoPtr, wParam, lParam); 03668 03669 case RB_MINIMIZEBAND: 03670 return REBAR_MinimizeBand (infoPtr, wParam); 03671 03672 case RB_MOVEBAND: 03673 return REBAR_MoveBand (infoPtr, wParam, lParam); 03674 03675 case RB_PUSHCHEVRON: 03676 return REBAR_PushChevron (infoPtr, wParam, lParam); 03677 03678 case RB_SETBANDINFOA: 03679 case RB_SETBANDINFOW: 03680 return REBAR_SetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 03681 uMsg == RB_SETBANDINFOW); 03682 case RB_SETBARINFO: 03683 return REBAR_SetBarInfo (infoPtr, (LPREBARINFO)lParam); 03684 03685 case RB_SETBKCOLOR: 03686 return REBAR_SetBkColor (infoPtr, lParam); 03687 03688 /* case RB_SETCOLORSCHEME: */ 03689 /* case RB_SETPALETTE: */ 03690 03691 case RB_SETPARENT: 03692 return REBAR_SetParent (infoPtr, (HWND)wParam); 03693 03694 case RB_SETTEXTCOLOR: 03695 return REBAR_SetTextColor (infoPtr, lParam); 03696 03697 /* case RB_SETTOOLTIPS: */ 03698 03699 case RB_SETUNICODEFORMAT: 03700 return REBAR_SetUnicodeFormat (infoPtr, wParam); 03701 03702 case CCM_SETVERSION: 03703 return REBAR_SetVersion (infoPtr, (INT)wParam); 03704 03705 case RB_SHOWBAND: 03706 return REBAR_ShowBand (infoPtr, wParam, lParam); 03707 03708 case RB_SIZETORECT: 03709 return REBAR_SizeToRect (infoPtr, (LPCRECT)lParam); 03710 03711 03712 /* Messages passed to parent */ 03713 case WM_COMMAND: 03714 case WM_DRAWITEM: 03715 case WM_NOTIFY: 03716 return SendMessageW(REBAR_GetNotifyParent (infoPtr), uMsg, wParam, lParam); 03717 03718 03719 /* case WM_CHARTOITEM: supported according to ControlSpy */ 03720 03721 case WM_CREATE: 03722 return REBAR_Create (infoPtr, (LPCREATESTRUCTW)lParam); 03723 03724 case WM_DESTROY: 03725 return REBAR_Destroy (infoPtr); 03726 03727 case WM_ERASEBKGND: 03728 return REBAR_EraseBkGnd (infoPtr, (HDC)wParam); 03729 03730 case WM_GETFONT: 03731 return REBAR_GetFont (infoPtr); 03732 03733 /* case WM_LBUTTONDBLCLK: supported according to ControlSpy */ 03734 03735 case WM_LBUTTONDOWN: 03736 return REBAR_LButtonDown (infoPtr, lParam); 03737 03738 case WM_LBUTTONUP: 03739 return REBAR_LButtonUp (infoPtr); 03740 03741 /* case WM_MEASUREITEM: supported according to ControlSpy */ 03742 03743 case WM_MOUSEMOVE: 03744 return REBAR_MouseMove (infoPtr, lParam); 03745 03746 case WM_MOUSELEAVE: 03747 return REBAR_MouseLeave (infoPtr); 03748 03749 case WM_NCCALCSIZE: 03750 return REBAR_NCCalcSize (infoPtr, (RECT*)lParam); 03751 03752 case WM_NCCREATE: 03753 return REBAR_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); 03754 03755 case WM_NCHITTEST: 03756 return REBAR_NCHitTest (infoPtr, lParam); 03757 03758 case WM_NCPAINT: 03759 return REBAR_NCPaint (infoPtr); 03760 03761 case WM_NOTIFYFORMAT: 03762 return REBAR_NotifyFormat (infoPtr, lParam); 03763 03764 case WM_PRINTCLIENT: 03765 case WM_PAINT: 03766 return REBAR_Paint (infoPtr, (HDC)wParam); 03767 03768 /* case WM_PALETTECHANGED: supported according to ControlSpy */ 03769 /* case WM_QUERYNEWPALETTE:supported according to ControlSpy */ 03770 /* case WM_RBUTTONDOWN: supported according to ControlSpy */ 03771 /* case WM_RBUTTONUP: supported according to ControlSpy */ 03772 03773 case WM_SETCURSOR: 03774 return REBAR_SetCursor (infoPtr, lParam); 03775 03776 case WM_SETFONT: 03777 return REBAR_SetFont (infoPtr, (HFONT)wParam); 03778 03779 case WM_SETREDRAW: 03780 return REBAR_SetRedraw (infoPtr, wParam); 03781 03782 case WM_SIZE: 03783 return REBAR_Size (infoPtr, wParam, lParam); 03784 03785 case WM_STYLECHANGED: 03786 return REBAR_StyleChanged (infoPtr, wParam, (LPSTYLESTRUCT)lParam); 03787 03788 case WM_THEMECHANGED: 03789 return theme_changed (infoPtr); 03790 03791 case WM_SYSCOLORCHANGE: 03792 COMCTL32_RefreshSysColors(); 03793 infoPtr->clrBtnText = comctl32_color.clrBtnText; 03794 infoPtr->clrBtnFace = comctl32_color.clrBtnFace; 03795 return 0; 03796 03797 /* case WM_VKEYTOITEM: supported according to ControlSpy */ 03798 /* case WM_WININICHANGE: */ 03799 03800 case WM_WINDOWPOSCHANGED: 03801 return REBAR_WindowPosChanged (infoPtr, wParam, lParam); 03802 03803 default: 03804 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 03805 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", 03806 uMsg, wParam, lParam); 03807 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 03808 } 03809 } 03810 03811 03812 VOID 03813 REBAR_Register (void) 03814 { 03815 WNDCLASSW wndClass; 03816 03817 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 03818 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; 03819 wndClass.lpfnWndProc = REBAR_WindowProc; 03820 wndClass.cbClsExtra = 0; 03821 wndClass.cbWndExtra = sizeof(REBAR_INFO *); 03822 wndClass.hCursor = 0; 03823 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 03824 #if GLATESTING 03825 wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0)); 03826 #endif 03827 wndClass.lpszClassName = REBARCLASSNAMEW; 03828 03829 RegisterClassW (&wndClass); 03830 03831 mindragx = GetSystemMetrics (SM_CXDRAG); 03832 mindragy = GetSystemMetrics (SM_CYDRAG); 03833 03834 } 03835 03836 03837 VOID 03838 REBAR_Unregister (void) 03839 { 03840 UnregisterClassW (REBARCLASSNAMEW, NULL); 03841 } Generated on Sat May 26 2012 04:21:37 for ReactOS by
1.7.6.1
|