1 /* 2 * Rebar control 3 * 4 * Copyright 1998, 1999 Eric Kohl 5 * Copyright 2007, 2008 Mikolaj Zalewski 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * NOTES 22 * 23 * This code was audited for completeness against the documented features 24 * of Comctl32.dll version 6.0 on Oct. 19, 2004, by Robert Shearman. 25 * 26 * Unless otherwise noted, we believe this code to be complete, as per 27 * the specification mentioned above. 28 * If you discover missing features or bugs please note them below. 29 * 30 * TODO 31 * Styles: 32 * - RBS_DBLCLKTOGGLE 33 * - RBS_FIXEDORDER 34 * - RBS_REGISTERDROP 35 * - RBS_TOOLTIPS 36 * Messages: 37 * - RB_BEGINDRAG 38 * - RB_DRAGMOVE 39 * - RB_ENDDRAG 40 * - RB_GETBANDMARGINS 41 * - RB_GETCOLORSCHEME 42 * - RB_GETDROPTARGET 43 * - RB_GETPALETTE 44 * - RB_SETCOLORSCHEME 45 * - RB_SETPALETTE 46 * - RB_SETTOOLTIPS 47 * - WM_CHARTOITEM 48 * - WM_LBUTTONDBLCLK 49 * - WM_PALETTECHANGED 50 * - WM_QUERYNEWPALETTE 51 * - WM_RBUTTONDOWN 52 * - WM_RBUTTONUP 53 * - WM_VKEYTOITEM 54 * - WM_WININICHANGE 55 * Notifications: 56 * - NM_HCHITTEST 57 * - NM_RELEASEDCAPTURE 58 * - RBN_AUTOBREAK 59 * - RBN_GETOBJECT 60 * - RBN_MINMAX 61 * Band styles: 62 * - RBBS_FIXEDBMP 63 * Native uses (on each draw!!) SM_CYBORDER (or SM_CXBORDER for CCS_VERT) 64 * to set the size of the separator width (the value SEP_WIDTH_SIZE 65 * in here). Should be fixed!! 66 */ 67 68 /* 69 * Testing: set to 1 to make background brush *always* green 70 */ 71 #define GLATESTING 0 72 73 /* 74 * 3. REBAR_MoveChildWindows should have a loop because more than 75 * one pass (together with the RBN_CHILDSIZEs) is made on 76 * at least RB_INSERTBAND 77 */ 78 79 #include <assert.h> 80 #include <stdarg.h> 81 #include <stdlib.h> 82 #include <string.h> 83 84 #include "windef.h" 85 #include "winbase.h" 86 #include "wingdi.h" 87 #include "winuser.h" 88 #include "winnls.h" 89 #include "commctrl.h" 90 #include "comctl32.h" 91 #include "uxtheme.h" 92 #include "vssym32.h" 93 #include "wine/debug.h" 94 95 WINE_DEFAULT_DEBUG_CHANNEL(rebar); 96 97 typedef struct 98 { 99 UINT fStyle; 100 UINT fMask; 101 COLORREF clrFore; 102 COLORREF clrBack; 103 INT iImage; 104 HWND hwndChild; 105 UINT cxMinChild; /* valid if _CHILDSIZE */ 106 UINT cyMinChild; /* valid if _CHILDSIZE */ 107 UINT cx; /* valid if _SIZE */ 108 HBITMAP hbmBack; 109 UINT wID; 110 UINT cyChild; /* valid if _CHILDSIZE */ 111 UINT cyMaxChild; /* valid if _CHILDSIZE */ 112 UINT cyIntegral; /* valid if _CHILDSIZE */ 113 UINT cxIdeal; 114 LPARAM lParam; 115 UINT cxHeader; 116 117 INT cxEffective; /* current cx for band */ 118 UINT cyHeader; /* the height of the header */ 119 UINT cxMinBand; /* minimum cx for band */ 120 UINT cyMinBand; /* minimum cy for band */ 121 122 UINT cyRowSoFar; /* for RBS_VARHEIGHT - the height of the row if it would break on this band (set by _Layout) */ 123 INT iRow; /* zero-based index of the row this band assigned to */ 124 UINT fStatus; /* status flags, reset only by _Validate */ 125 UINT fDraw; /* drawing flags, reset only by _Layout */ 126 UINT uCDret; /* last return from NM_CUSTOMDRAW */ 127 RECT rcBand; /* calculated band rectangle - coordinates swapped for CCS_VERT */ 128 RECT rcGripper; /* calculated gripper rectangle */ 129 RECT rcCapImage; /* calculated caption image rectangle */ 130 RECT rcCapText; /* calculated caption text rectangle */ 131 RECT rcChild; /* calculated child rectangle */ 132 RECT rcChevron; /* calculated chevron rectangle */ 133 134 LPWSTR lpText; 135 HWND hwndPrevParent; 136 } REBAR_BAND; 137 138 /* has a value of: 0, CCS_TOP, CCS_NOMOVEY, CCS_BOTTOM */ 139 #define CCS_LAYOUT_MASK 0x3 140 141 /* fStatus flags */ 142 #define HAS_GRIPPER 0x00000001 143 #define HAS_IMAGE 0x00000002 144 #define HAS_TEXT 0x00000004 145 146 /* fDraw flags */ 147 #define DRAW_GRIPPER 0x00000001 148 #define DRAW_IMAGE 0x00000002 149 #define DRAW_TEXT 0x00000004 150 #define DRAW_CHEVRONHOT 0x00000040 151 #define DRAW_CHEVRONPUSHED 0x00000080 152 #define NTF_INVALIDATE 0x01000000 153 154 typedef struct 155 { 156 COLORREF clrBk; /* background color */ 157 COLORREF clrText; /* text color */ 158 COLORREF clrBtnText; /* system color for BTNTEXT */ 159 COLORREF clrBtnFace; /* system color for BTNFACE */ 160 HIMAGELIST himl; /* handle to imagelist */ 161 UINT uNumBands; /* # of bands in rebar (first=0, last=uNumBands-1 */ 162 UINT uNumRows; /* # of rows of bands (first=1, last=uNumRows */ 163 HWND hwndSelf; /* handle of REBAR window itself */ 164 HWND hwndToolTip; /* handle to the tool tip control */ 165 HWND hwndNotify; /* notification window (parent) */ 166 HFONT hDefaultFont; 167 HFONT hFont; /* handle to the rebar's font */ 168 SIZE imageSize; /* image size (image list) */ 169 DWORD dwStyle; /* window style */ 170 DWORD orgStyle; /* original style (dwStyle may change) */ 171 SIZE calcSize; /* calculated rebar size - coordinates swapped for CCS_VERT */ 172 BOOL bUnicode; /* TRUE if parent wants notify in W format */ 173 BOOL DoRedraw; /* TRUE to actually draw bands */ 174 UINT fStatus; /* Status flags (see below) */ 175 HCURSOR hcurArrow; /* handle to the arrow cursor */ 176 HCURSOR hcurHorz; /* handle to the EW cursor */ 177 HCURSOR hcurVert; /* handle to the NS cursor */ 178 HCURSOR hcurDrag; /* handle to the drag cursor */ 179 INT iVersion; /* version number */ 180 POINT dragStart; /* x,y of button down */ 181 POINT dragNow; /* x,y of this MouseMove */ 182 INT iOldBand; /* last band that had the mouse cursor over it */ 183 INT ihitoffset; /* offset of hotspot from gripper.left */ 184 INT ichevronhotBand; /* last band that had a hot chevron */ 185 INT iGrabbedBand;/* band number of band whose gripper was grabbed */ 186 187 HDPA bands; /* pointer to the array of rebar bands */ 188 } REBAR_INFO; 189 190 /* fStatus flags */ 191 #define BEGIN_DRAG_ISSUED 0x00000001 192 #define SELF_RESIZE 0x00000002 193 #define BAND_NEEDS_REDRAW 0x00000020 194 195 /* used by Windows to mark that the header size has been set by the user and shouldn't be changed */ 196 #define RBBS_UNDOC_FIXEDHEADER 0x40000000 197 198 /* ---- REBAR layout constants. Mostly determined by ---- */ 199 /* ---- experiment on WIN 98. ---- */ 200 201 /* Width (or height) of separators between bands (either horz. or */ 202 /* vert.). True only if RBS_BANDBORDERS is set */ 203 #define SEP_WIDTH_SIZE 2 204 #define SEP_WIDTH ((infoPtr->dwStyle & RBS_BANDBORDERS) ? SEP_WIDTH_SIZE : 0) 205 206 /* Blank (background color) space between Gripper (if present) */ 207 /* and next item (image, text, or window). Always present */ 208 #define REBAR_ALWAYS_SPACE 4 209 210 /* Blank (background color) space after Image (if present). */ 211 #define REBAR_POST_IMAGE 2 212 213 /* Blank (background color) space after Text (if present). */ 214 #define REBAR_POST_TEXT 4 215 216 /* Height of vertical gripper in a CCS_VERT rebar. */ 217 #define GRIPPER_HEIGHT 16 218 219 /* Blank (background color) space before Gripper (if present). */ 220 #define REBAR_PRE_GRIPPER 2 221 222 /* Width (of normal vertical gripper) or height (of horz. gripper) */ 223 /* if present. */ 224 #define GRIPPER_WIDTH 3 225 226 /* Width of the chevron button if present */ 227 #define CHEVRON_WIDTH 10 228 229 /* the gap between the child and the next band */ 230 #define REBAR_POST_CHILD 4 231 232 /* Height of divider for Rebar if not disabled (CCS_NODIVIDER) */ 233 /* either top or bottom */ 234 #define REBAR_DIVIDER 2 235 236 /* height of a rebar without a child */ 237 #define REBAR_NO_CHILD_HEIGHT 4 238 239 /* minimum vertical height of a normal bar */ 240 /* or minimum width of a CCS_VERT bar - from experiment on Win2k */ 241 #define REBAR_MINSIZE 23 242 243 /* This is the increment that is used over the band height */ 244 #define REBARSPACE(a) ((a->fStyle & RBBS_CHILDEDGE) ? 2*REBAR_DIVIDER : 0) 245 246 /* ---- End of REBAR layout constants. ---- */ 247 248 #define RB_GETBANDINFO_OLD (WM_USER+5) /* obsoleted after IE3, but we have to support it anyway */ 249 250 /* The following define determines if a given band is hidden */ 251 #define HIDDENBAND(a) (((a)->fStyle & RBBS_HIDDEN) || \ 252 ((infoPtr->dwStyle & CCS_VERT) && \ 253 ((a)->fStyle & RBBS_NOVERT))) 254 255 #define REBAR_GetInfoPtr(wndPtr) ((REBAR_INFO *)GetWindowLongPtrW (hwnd, 0)) 256 257 static LRESULT REBAR_NotifyFormat(REBAR_INFO *infoPtr, LPARAM lParam); 258 static void REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout); 259 260 /* no index check here */ 261 static inline REBAR_BAND* REBAR_GetBand(const REBAR_INFO *infoPtr, INT i) 262 { 263 assert(i >= 0 && i < infoPtr->uNumBands); 264 return DPA_GetPtr(infoPtr->bands, i); 265 } 266 267 /* "constant values" retrieved when DLL was initialized */ 268 /* FIXME we do this when the classes are registered. */ 269 static UINT mindragx = 0; 270 static UINT mindragy = 0; 271 272 static const char * const band_stylename[] = { 273 "RBBS_BREAK", /* 0001 */ 274 "RBBS_FIXEDSIZE", /* 0002 */ 275 "RBBS_CHILDEDGE", /* 0004 */ 276 "RBBS_HIDDEN", /* 0008 */ 277 "RBBS_NOVERT", /* 0010 */ 278 "RBBS_FIXEDBMP", /* 0020 */ 279 "RBBS_VARIABLEHEIGHT", /* 0040 */ 280 "RBBS_GRIPPERALWAYS", /* 0080 */ 281 "RBBS_NOGRIPPER", /* 0100 */ 282 "RBBS_USECHEVRON", /* 0200 */ 283 "RBBS_HIDETITLE", /* 0400 */ 284 "RBBS_TOPALIGN", /* 0800 */ 285 NULL }; 286 287 static const char * const band_maskname[] = { 288 "RBBIM_STYLE", /* 0x00000001 */ 289 "RBBIM_COLORS", /* 0x00000002 */ 290 "RBBIM_TEXT", /* 0x00000004 */ 291 "RBBIM_IMAGE", /* 0x00000008 */ 292 "RBBIM_CHILD", /* 0x00000010 */ 293 "RBBIM_CHILDSIZE", /* 0x00000020 */ 294 "RBBIM_SIZE", /* 0x00000040 */ 295 "RBBIM_BACKGROUND", /* 0x00000080 */ 296 "RBBIM_ID", /* 0x00000100 */ 297 "RBBIM_IDEALSIZE", /* 0x00000200 */ 298 "RBBIM_LPARAM", /* 0x00000400 */ 299 "RBBIM_HEADERSIZE", /* 0x00000800 */ 300 "RBBIM_CHEVRONLOCATION", /* 0x00001000 */ 301 "RBBIM_CHEVRONSTATE", /* 0x00002000 */ 302 NULL }; 303 304 305 static const WCHAR themeClass[] = { 'R','e','b','a','r',0 }; 306 307 static CHAR * 308 REBAR_FmtStyle(char *buffer, UINT style) 309 { 310 INT i = 0; 311 312 *buffer = 0; 313 while (band_stylename[i]) { 314 if (style & (1<<i)) { 315 if (*buffer) strcat(buffer, " | "); 316 strcat(buffer, band_stylename[i]); 317 } 318 i++; 319 } 320 return buffer; 321 } 322 323 324 static CHAR * 325 REBAR_FmtMask(char *buffer, UINT mask) 326 { 327 INT i = 0; 328 329 *buffer = 0; 330 while (band_maskname[i]) { 331 if (mask & (1<<i)) { 332 if (*buffer) strcat(buffer, " | "); 333 strcat(buffer, band_maskname[i]); 334 } 335 i++; 336 } 337 return buffer; 338 } 339 340 341 static VOID 342 REBAR_DumpBandInfo(const REBARBANDINFOW *pB) 343 { 344 char buff[300]; 345 346 if( !TRACE_ON(rebar) ) return; 347 TRACE("band info: "); 348 if (pB->fMask & RBBIM_ID) 349 TRACE("ID=%u, ", pB->wID); 350 TRACE("size=%u, child=%p", pB->cbSize, pB->hwndChild); 351 if (pB->fMask & RBBIM_COLORS) 352 TRACE(", clrF=0x%06x, clrB=0x%06x", pB->clrFore, pB->clrBack); 353 TRACE("\n"); 354 355 TRACE("band info: mask=0x%08x (%s)\n", pB->fMask, REBAR_FmtMask(buff, pB->fMask)); 356 if (pB->fMask & RBBIM_STYLE) 357 TRACE("band info: style=0x%08x (%s)\n", pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle)); 358 if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_HEADERSIZE | RBBIM_LPARAM )) { 359 TRACE("band info:"); 360 if (pB->fMask & RBBIM_SIZE) 361 TRACE(" cx=%u", pB->cx); 362 if (pB->fMask & RBBIM_IDEALSIZE) 363 TRACE(" xIdeal=%u", pB->cxIdeal); 364 if (pB->fMask & RBBIM_HEADERSIZE) 365 TRACE(" xHeader=%u", pB->cxHeader); 366 if (pB->fMask & RBBIM_LPARAM) 367 TRACE(" lParam=0x%08lx", pB->lParam); 368 TRACE("\n"); 369 } 370 if (pB->fMask & RBBIM_CHILDSIZE) 371 TRACE("band info: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", 372 pB->cxMinChild, 373 pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); 374 } 375 376 static VOID 377 REBAR_DumpBand (const REBAR_INFO *iP) 378 { 379 char buff[300]; 380 REBAR_BAND *pB; 381 UINT i; 382 383 if(! TRACE_ON(rebar) ) return; 384 385 TRACE("hwnd=%p: color=%08x/%08x, bands=%u, rows=%u, cSize=%d,%d\n", 386 iP->hwndSelf, iP->clrText, iP->clrBk, iP->uNumBands, iP->uNumRows, 387 iP->calcSize.cx, iP->calcSize.cy); 388 TRACE("hwnd=%p: flags=%08x, dragStart=%d,%d, dragNow=%d,%d, iGrabbedBand=%d\n", 389 iP->hwndSelf, iP->fStatus, iP->dragStart.x, iP->dragStart.y, 390 iP->dragNow.x, iP->dragNow.y, 391 iP->iGrabbedBand); 392 TRACE("hwnd=%p: style=%08x, notify in Unicode=%s, redraw=%s\n", 393 iP->hwndSelf, iP->dwStyle, (iP->bUnicode)?"TRUE":"FALSE", 394 (iP->DoRedraw)?"TRUE":"FALSE"); 395 for (i = 0; i < iP->uNumBands; i++) { 396 pB = REBAR_GetBand(iP, i); 397 TRACE("band # %u:", i); 398 if (pB->fMask & RBBIM_ID) 399 TRACE(" ID=%u", pB->wID); 400 if (pB->fMask & RBBIM_CHILD) 401 TRACE(" child=%p", pB->hwndChild); 402 if (pB->fMask & RBBIM_COLORS) 403 TRACE(" clrF=0x%06x clrB=0x%06x", pB->clrFore, pB->clrBack); 404 TRACE("\n"); 405 TRACE("band # %u: mask=0x%08x (%s)\n", i, pB->fMask, REBAR_FmtMask(buff, pB->fMask)); 406 if (pB->fMask & RBBIM_STYLE) 407 TRACE("band # %u: style=0x%08x (%s)\n", i, pB->fStyle, REBAR_FmtStyle(buff, pB->fStyle)); 408 TRACE("band # %u: xHeader=%u", 409 i, pB->cxHeader); 410 if (pB->fMask & (RBBIM_SIZE | RBBIM_IDEALSIZE | RBBIM_LPARAM )) { 411 if (pB->fMask & RBBIM_SIZE) 412 TRACE(" cx=%u", pB->cx); 413 if (pB->fMask & RBBIM_IDEALSIZE) 414 TRACE(" xIdeal=%u", pB->cxIdeal); 415 if (pB->fMask & RBBIM_LPARAM) 416 TRACE(" lParam=0x%08lx", pB->lParam); 417 } 418 TRACE("\n"); 419 if (RBBIM_CHILDSIZE) 420 TRACE("band # %u: xMin=%u, yMin=%u, yChild=%u, yMax=%u, yIntgl=%u\n", 421 i, pB->cxMinChild, pB->cyMinChild, pB->cyChild, pB->cyMaxChild, pB->cyIntegral); 422 if (pB->fMask & RBBIM_TEXT) 423 TRACE("band # %u: text=%s\n", 424 i, (pB->lpText) ? debugstr_w(pB->lpText) : "(null)"); 425 TRACE("band # %u: cxMinBand=%u, cxEffective=%u, cyMinBand=%u\n", 426 i, pB->cxMinBand, pB->cxEffective, pB->cyMinBand); 427 TRACE("band # %u: fStatus=%08x, fDraw=%08x, Band=(%s), Grip=(%s)\n", 428 i, pB->fStatus, pB->fDraw, wine_dbgstr_rect(&pB->rcBand), 429 wine_dbgstr_rect(&pB->rcGripper)); 430 TRACE("band # %u: Img=(%s), Txt=(%s), Child=(%s)\n", 431 i, wine_dbgstr_rect(&pB->rcCapImage), 432 wine_dbgstr_rect(&pB->rcCapText), wine_dbgstr_rect(&pB->rcChild)); 433 } 434 435 } 436 437 /* dest can be equal to src */ 438 static void translate_rect(const REBAR_INFO *infoPtr, RECT *dest, const RECT *src) 439 { 440 if (infoPtr->dwStyle & CCS_VERT) { 441 int tmp; 442 tmp = src->left; 443 dest->left = src->top; 444 dest->top = tmp; 445 446 tmp = src->right; 447 dest->right = src->bottom; 448 dest->bottom = tmp; 449 } else { 450 *dest = *src; 451 } 452 } 453 454 static int get_rect_cx(const REBAR_INFO *infoPtr, const RECT *lpRect) 455 { 456 if (infoPtr->dwStyle & CCS_VERT) 457 return lpRect->bottom - lpRect->top; 458 return lpRect->right - lpRect->left; 459 } 460 461 static int get_rect_cy(const REBAR_INFO *infoPtr, const RECT *lpRect) 462 { 463 if (infoPtr->dwStyle & CCS_VERT) 464 return lpRect->right - lpRect->left; 465 return lpRect->bottom - lpRect->top; 466 } 467 468 static int round_child_height(const REBAR_BAND *lpBand, int cyHeight) 469 { 470 int cy = 0; 471 if (lpBand->cyIntegral == 0) 472 return cyHeight; 473 cy = max(cyHeight - (int)lpBand->cyMinChild, 0); 474 cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral; 475 cy = min(cy, lpBand->cyMaxChild); 476 return cy; 477 } 478 479 static void update_min_band_height(const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 480 { 481 lpBand->cyMinBand = max(lpBand->cyHeader, 482 (lpBand->hwndChild ? lpBand->cyChild + REBARSPACE(lpBand) : REBAR_NO_CHILD_HEIGHT)); 483 } 484 485 static void 486 REBAR_DrawChevron (HDC hdc, INT left, INT top, INT colorRef) 487 { 488 INT x, y; 489 HPEN hPen, hOldPen; 490 491 if (!(hPen = CreatePen( PS_SOLID, 1, GetSysColor( colorRef )))) return; 492 hOldPen = SelectObject ( hdc, hPen ); 493 x = left + 2; 494 y = top; 495 MoveToEx (hdc, x, y, NULL); 496 LineTo (hdc, x+5, y++); x++; 497 MoveToEx (hdc, x, y, NULL); 498 LineTo (hdc, x+3, y++); x++; 499 MoveToEx (hdc, x, y, NULL); 500 LineTo (hdc, x+1, y); 501 SelectObject( hdc, hOldPen ); 502 DeleteObject( hPen ); 503 } 504 505 static HWND 506 REBAR_GetNotifyParent (const REBAR_INFO *infoPtr) 507 { 508 HWND parent, owner; 509 510 parent = infoPtr->hwndNotify; 511 if (!parent) { 512 parent = GetParent (infoPtr->hwndSelf); 513 owner = GetWindow (infoPtr->hwndSelf, GW_OWNER); 514 if (owner) parent = owner; 515 } 516 return parent; 517 } 518 519 520 static INT 521 REBAR_Notify (NMHDR *nmhdr, const REBAR_INFO *infoPtr, UINT code) 522 { 523 HWND parent; 524 525 parent = REBAR_GetNotifyParent (infoPtr); 526 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); 527 nmhdr->hwndFrom = infoPtr->hwndSelf; 528 nmhdr->code = code; 529 530 TRACE("window %p, code=%08x, via %s\n", parent, code, (infoPtr->bUnicode)?"Unicode":"ANSI"); 531 532 return SendMessageW(parent, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr); 533 } 534 535 static INT 536 REBAR_Notify_NMREBAR (const REBAR_INFO *infoPtr, UINT uBand, UINT code) 537 { 538 NMREBAR notify_rebar; 539 540 notify_rebar.dwMask = 0; 541 if (uBand != -1) { 542 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand); 543 544 if (lpBand->fMask & RBBIM_ID) { 545 notify_rebar.dwMask |= RBNM_ID; 546 notify_rebar.wID = lpBand->wID; 547 } 548 if (lpBand->fMask & RBBIM_LPARAM) { 549 notify_rebar.dwMask |= RBNM_LPARAM; 550 notify_rebar.lParam = lpBand->lParam; 551 } 552 if (lpBand->fMask & RBBIM_STYLE) { 553 notify_rebar.dwMask |= RBNM_STYLE; 554 notify_rebar.fStyle = lpBand->fStyle; 555 } 556 } 557 notify_rebar.uBand = uBand; 558 return REBAR_Notify ((NMHDR *)¬ify_rebar, infoPtr, code); 559 } 560 561 static VOID 562 REBAR_DrawBand (HDC hdc, const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 563 { 564 HFONT hOldFont = 0; 565 INT oldBkMode = 0; 566 NMCUSTOMDRAW nmcd; 567 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 568 RECT rcBand; 569 570 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 571 572 if (lpBand->fDraw & DRAW_TEXT) { 573 hOldFont = SelectObject (hdc, infoPtr->hFont); 574 oldBkMode = SetBkMode (hdc, TRANSPARENT); 575 } 576 577 /* should test for CDRF_NOTIFYITEMDRAW here */ 578 nmcd.dwDrawStage = CDDS_ITEMPREPAINT; 579 nmcd.hdc = hdc; 580 nmcd.rc = rcBand; 581 nmcd.rc.right = lpBand->rcCapText.right; 582 nmcd.rc.bottom = lpBand->rcCapText.bottom; 583 nmcd.dwItemSpec = lpBand->wID; 584 nmcd.uItemState = 0; 585 nmcd.lItemlParam = lpBand->lParam; 586 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); 587 if (lpBand->uCDret == CDRF_SKIPDEFAULT) { 588 if (oldBkMode != TRANSPARENT) 589 SetBkMode (hdc, oldBkMode); 590 SelectObject (hdc, hOldFont); 591 return; 592 } 593 594 /* draw gripper */ 595 if (lpBand->fDraw & DRAW_GRIPPER) 596 { 597 if (theme) 598 { 599 RECT rcGripper = lpBand->rcGripper; 600 int partId = (infoPtr->dwStyle & CCS_VERT) ? RP_GRIPPERVERT : RP_GRIPPER; 601 GetThemeBackgroundExtent (theme, hdc, partId, 0, &rcGripper, &rcGripper); 602 OffsetRect (&rcGripper, lpBand->rcGripper.left - rcGripper.left, 603 lpBand->rcGripper.top - rcGripper.top); 604 DrawThemeBackground (theme, hdc, partId, 0, &rcGripper, NULL); 605 } 606 else 607 DrawEdge (hdc, &lpBand->rcGripper, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); 608 } 609 610 /* draw caption image */ 611 if (lpBand->fDraw & DRAW_IMAGE) { 612 POINT pt; 613 614 /* center image */ 615 pt.y = (lpBand->rcCapImage.bottom + lpBand->rcCapImage.top - infoPtr->imageSize.cy)/2; 616 pt.x = (lpBand->rcCapImage.right + lpBand->rcCapImage.left - infoPtr->imageSize.cx)/2; 617 618 ImageList_Draw (infoPtr->himl, lpBand->iImage, hdc, 619 pt.x, pt.y, 620 ILD_TRANSPARENT); 621 } 622 623 /* draw caption text */ 624 if (lpBand->fDraw & DRAW_TEXT) { 625 /* need to handle CDRF_NEWFONT here */ 626 INT oldBkMode = SetBkMode (hdc, TRANSPARENT); 627 COLORREF oldcolor = CLR_NONE; 628 COLORREF new; 629 if (lpBand->clrFore != CLR_NONE) { 630 new = (lpBand->clrFore == CLR_DEFAULT) ? infoPtr->clrBtnText : 631 lpBand->clrFore; 632 oldcolor = SetTextColor (hdc, new); 633 } 634 635 #ifdef __REACTOS__ 636 if (!theme) 637 { 638 DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, DT_CENTER | DT_VCENTER | DT_SINGLELINE); 639 } 640 else 641 { 642 DrawThemeText(theme, hdc, 0, 0, lpBand->lpText, -1, DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &lpBand->rcCapText); 643 } 644 #else 645 DrawTextW (hdc, lpBand->lpText, -1, &lpBand->rcCapText, 646 DT_CENTER | DT_VCENTER | DT_SINGLELINE); 647 #endif 648 649 if (oldBkMode != TRANSPARENT) 650 SetBkMode (hdc, oldBkMode); 651 if (lpBand->clrFore != CLR_NONE) 652 SetTextColor (hdc, oldcolor); 653 SelectObject (hdc, hOldFont); 654 } 655 656 if (!IsRectEmpty(&lpBand->rcChevron)) 657 { 658 if (theme) 659 { 660 int stateId; 661 if (lpBand->fDraw & DRAW_CHEVRONPUSHED) 662 stateId = CHEVS_PRESSED; 663 else if (lpBand->fDraw & DRAW_CHEVRONHOT) 664 stateId = CHEVS_HOT; 665 else 666 stateId = CHEVS_NORMAL; 667 DrawThemeBackground (theme, hdc, RP_CHEVRON, stateId, &lpBand->rcChevron, NULL); 668 } 669 else 670 { 671 if (lpBand->fDraw & DRAW_CHEVRONPUSHED) 672 { 673 DrawEdge(hdc, &lpBand->rcChevron, BDR_SUNKENOUTER, BF_RECT | BF_MIDDLE); 674 REBAR_DrawChevron(hdc, lpBand->rcChevron.left+1, lpBand->rcChevron.top + 11, COLOR_WINDOWFRAME); 675 } 676 else if (lpBand->fDraw & DRAW_CHEVRONHOT) 677 { 678 DrawEdge(hdc, &lpBand->rcChevron, BDR_RAISEDINNER, BF_RECT | BF_MIDDLE); 679 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); 680 } 681 else 682 REBAR_DrawChevron(hdc, lpBand->rcChevron.left, lpBand->rcChevron.top + 10, COLOR_WINDOWFRAME); 683 } 684 } 685 686 if (lpBand->uCDret == (CDRF_NOTIFYPOSTPAINT | CDRF_NOTIFYITEMDRAW)) { 687 nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; 688 nmcd.hdc = hdc; 689 nmcd.rc = rcBand; 690 nmcd.rc.right = lpBand->rcCapText.right; 691 nmcd.rc.bottom = lpBand->rcCapText.bottom; 692 nmcd.dwItemSpec = lpBand->wID; 693 nmcd.uItemState = 0; 694 nmcd.lItemlParam = lpBand->lParam; 695 lpBand->uCDret = REBAR_Notify ((NMHDR *)&nmcd, infoPtr, NM_CUSTOMDRAW); 696 } 697 } 698 699 700 static VOID 701 REBAR_Refresh (const REBAR_INFO *infoPtr, HDC hdc) 702 { 703 REBAR_BAND *lpBand; 704 UINT i; 705 706 if (!infoPtr->DoRedraw) return; 707 708 for (i = 0; i < infoPtr->uNumBands; i++) { 709 lpBand = REBAR_GetBand(infoPtr, i); 710 711 if (HIDDENBAND(lpBand)) continue; 712 713 /* now draw the band */ 714 TRACE("[%p] drawing band %i, flags=%08x\n", 715 infoPtr->hwndSelf, i, lpBand->fDraw); 716 REBAR_DrawBand (hdc, infoPtr, lpBand); 717 } 718 } 719 720 721 static void 722 REBAR_CalcHorzBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend) 723 /* Function: this routine initializes all the rectangles in */ 724 /* each band in a row to fit in the adjusted rcBand rect. */ 725 /* *** Supports only Horizontal bars. *** */ 726 { 727 REBAR_BAND *lpBand; 728 UINT i, xoff; 729 RECT work; 730 731 for(i=rstart; i<rend; i++){ 732 lpBand = REBAR_GetBand(infoPtr, i); 733 if (HIDDENBAND(lpBand)) { 734 SetRect (&lpBand->rcChild, 735 lpBand->rcBand.right, lpBand->rcBand.top, 736 lpBand->rcBand.right, lpBand->rcBand.bottom); 737 continue; 738 } 739 740 /* set initial gripper rectangle */ 741 SetRect (&lpBand->rcGripper, lpBand->rcBand.left, lpBand->rcBand.top, 742 lpBand->rcBand.left, lpBand->rcBand.bottom); 743 744 /* calculate gripper rectangle */ 745 if ( lpBand->fStatus & HAS_GRIPPER) { 746 lpBand->fDraw |= DRAW_GRIPPER; 747 lpBand->rcGripper.left += REBAR_PRE_GRIPPER; 748 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; 749 InflateRect(&lpBand->rcGripper, 0, -2); 750 751 SetRect (&lpBand->rcCapImage, 752 lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.top, 753 lpBand->rcGripper.right+REBAR_ALWAYS_SPACE, lpBand->rcBand.bottom); 754 } 755 else { /* no gripper will be drawn */ 756 xoff = 0; 757 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) 758 /* if no gripper but either image or text, then leave space */ 759 xoff = REBAR_ALWAYS_SPACE; 760 SetRect (&lpBand->rcCapImage, 761 lpBand->rcBand.left+xoff, lpBand->rcBand.top, 762 lpBand->rcBand.left+xoff, lpBand->rcBand.bottom); 763 } 764 765 /* image is visible */ 766 if (lpBand->fStatus & HAS_IMAGE) { 767 lpBand->fDraw |= DRAW_IMAGE; 768 lpBand->rcCapImage.right += infoPtr->imageSize.cx; 769 lpBand->rcCapImage.bottom = lpBand->rcCapImage.top + infoPtr->imageSize.cy; 770 771 /* set initial caption text rectangle */ 772 SetRect (&lpBand->rcCapText, 773 lpBand->rcCapImage.right+REBAR_POST_IMAGE, lpBand->rcBand.top+1, 774 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); 775 } 776 else { 777 /* set initial caption text rectangle */ 778 SetRect (&lpBand->rcCapText, lpBand->rcCapImage.right, lpBand->rcBand.top+1, 779 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.bottom-1); 780 } 781 782 /* text is visible */ 783 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { 784 lpBand->fDraw |= DRAW_TEXT; 785 lpBand->rcCapText.right = max(lpBand->rcCapText.left, 786 lpBand->rcCapText.right-REBAR_POST_TEXT); 787 } 788 789 /* set initial child window rectangle if there is a child */ 790 if (lpBand->hwndChild) { 791 792 lpBand->rcChild.left = lpBand->rcBand.left + lpBand->cxHeader; 793 lpBand->rcChild.right = lpBand->rcBand.right - REBAR_POST_CHILD; 794 795 if (lpBand->cyChild > 0) { 796 797 UINT yoff = (lpBand->rcBand.bottom - lpBand->rcBand.top - lpBand->cyChild) / 2; 798 799 /* center child if height is known */ 800 lpBand->rcChild.top = lpBand->rcBand.top + yoff; 801 lpBand->rcChild.bottom = lpBand->rcBand.top + yoff + lpBand->cyChild; 802 } 803 else { 804 lpBand->rcChild.top = lpBand->rcBand.top; 805 lpBand->rcChild.bottom = lpBand->rcBand.bottom; 806 } 807 808 if ((lpBand->fStyle & RBBS_USECHEVRON) && (lpBand->rcChild.right - lpBand->rcChild.left < lpBand->cxIdeal)) 809 { 810 lpBand->rcChild.right -= CHEVRON_WIDTH; 811 SetRect(&lpBand->rcChevron, lpBand->rcChild.right, 812 lpBand->rcChild.top, lpBand->rcChild.right + CHEVRON_WIDTH, 813 lpBand->rcChild.bottom); 814 } 815 } 816 else { 817 SetRect (&lpBand->rcChild, 818 lpBand->rcBand.left+lpBand->cxHeader, lpBand->rcBand.top, 819 lpBand->rcBand.right, lpBand->rcBand.bottom); 820 } 821 822 /* flag if notify required and invalidate rectangle */ 823 if (lpBand->fDraw & NTF_INVALIDATE) { 824 lpBand->fDraw &= ~NTF_INVALIDATE; 825 work = lpBand->rcBand; 826 work.right += SEP_WIDTH; 827 work.bottom += SEP_WIDTH; 828 TRACE("invalidating %s\n", wine_dbgstr_rect(&work)); 829 InvalidateRect(infoPtr->hwndSelf, &work, TRUE); 830 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE); 831 } 832 833 } 834 835 } 836 837 838 static VOID 839 REBAR_CalcVertBand (const REBAR_INFO *infoPtr, UINT rstart, UINT rend) 840 /* Function: this routine initializes all the rectangles in */ 841 /* each band in a row to fit in the adjusted rcBand rect. */ 842 /* *** Supports only Vertical bars. *** */ 843 { 844 REBAR_BAND *lpBand; 845 UINT i, xoff; 846 RECT work; 847 848 for(i=rstart; i<rend; i++){ 849 RECT rcBand; 850 lpBand = REBAR_GetBand(infoPtr, i); 851 if (HIDDENBAND(lpBand)) continue; 852 853 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 854 855 /* set initial gripper rectangle */ 856 SetRect (&lpBand->rcGripper, rcBand.left, rcBand.top, rcBand.right, rcBand.top); 857 858 /* calculate gripper rectangle */ 859 if (lpBand->fStatus & HAS_GRIPPER) { 860 lpBand->fDraw |= DRAW_GRIPPER; 861 862 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) { 863 /* vertical gripper */ 864 lpBand->rcGripper.left += 3; 865 lpBand->rcGripper.right = lpBand->rcGripper.left + GRIPPER_WIDTH; 866 lpBand->rcGripper.top += REBAR_PRE_GRIPPER; 867 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_HEIGHT; 868 869 /* initialize Caption image rectangle */ 870 SetRect (&lpBand->rcCapImage, rcBand.left, 871 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, 872 rcBand.right, 873 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); 874 } 875 else { 876 /* horizontal gripper */ 877 InflateRect(&lpBand->rcGripper, -2, 0); 878 lpBand->rcGripper.top += REBAR_PRE_GRIPPER; 879 lpBand->rcGripper.bottom = lpBand->rcGripper.top + GRIPPER_WIDTH; 880 881 /* initialize Caption image rectangle */ 882 SetRect (&lpBand->rcCapImage, rcBand.left, 883 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE, 884 rcBand.right, 885 lpBand->rcGripper.bottom + REBAR_ALWAYS_SPACE); 886 } 887 } 888 else { /* no gripper will be drawn */ 889 xoff = 0; 890 if (lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) 891 /* if no gripper but either image or text, then leave space */ 892 xoff = REBAR_ALWAYS_SPACE; 893 /* initialize Caption image rectangle */ 894 SetRect (&lpBand->rcCapImage, 895 rcBand.left, rcBand.top+xoff, 896 rcBand.right, rcBand.top+xoff); 897 } 898 899 /* image is visible */ 900 if (lpBand->fStatus & HAS_IMAGE) { 901 lpBand->fDraw |= DRAW_IMAGE; 902 903 lpBand->rcCapImage.right = lpBand->rcCapImage.left + infoPtr->imageSize.cx; 904 lpBand->rcCapImage.bottom += infoPtr->imageSize.cy; 905 906 /* set initial caption text rectangle */ 907 SetRect (&lpBand->rcCapText, 908 rcBand.left, lpBand->rcCapImage.bottom+REBAR_POST_IMAGE, 909 rcBand.right, rcBand.top+lpBand->cxHeader); 910 } 911 else { 912 /* set initial caption text rectangle */ 913 SetRect (&lpBand->rcCapText, 914 rcBand.left, lpBand->rcCapImage.bottom, 915 rcBand.right, rcBand.top+lpBand->cxHeader); 916 } 917 918 /* text is visible */ 919 if ((lpBand->fStatus & HAS_TEXT) && !(lpBand->fStyle & RBBS_HIDETITLE)) { 920 lpBand->fDraw |= DRAW_TEXT; 921 lpBand->rcCapText.bottom = max(lpBand->rcCapText.top, 922 lpBand->rcCapText.bottom); 923 } 924 925 /* set initial child window rectangle if there is a child */ 926 if (lpBand->hwndChild) { 927 int cxBand = rcBand.right - rcBand.left; 928 xoff = (cxBand - lpBand->cyChild) / 2; 929 SetRect (&lpBand->rcChild, 930 rcBand.left + xoff, rcBand.top + lpBand->cxHeader, 931 rcBand.left + xoff + lpBand->cyChild, rcBand.bottom - REBAR_POST_CHILD); 932 } 933 else { 934 SetRect (&lpBand->rcChild, 935 rcBand.left, rcBand.top+lpBand->cxHeader, 936 rcBand.right, rcBand.bottom); 937 } 938 939 if (lpBand->fDraw & NTF_INVALIDATE) { 940 lpBand->fDraw &= ~NTF_INVALIDATE; 941 work = rcBand; 942 work.bottom += SEP_WIDTH; 943 work.right += SEP_WIDTH; 944 TRACE("invalidating %s\n", wine_dbgstr_rect(&work)); 945 InvalidateRect(infoPtr->hwndSelf, &work, TRUE); 946 if (lpBand->hwndChild) InvalidateRect(lpBand->hwndChild, NULL, TRUE); 947 } 948 949 } 950 } 951 952 953 static VOID 954 REBAR_ForceResize (REBAR_INFO *infoPtr) 955 /* Function: This changes the size of the REBAR window to that */ 956 /* calculated by REBAR_Layout. */ 957 { 958 INT x, y, width, height; 959 INT xedge = 0, yedge = 0; 960 RECT rcSelf; 961 962 TRACE("new size [%d x %d]\n", infoPtr->calcSize.cx, infoPtr->calcSize.cy); 963 964 if (infoPtr->dwStyle & CCS_NORESIZE) 965 return; 966 967 if (infoPtr->dwStyle & WS_BORDER) 968 { 969 xedge = GetSystemMetrics(SM_CXEDGE); 970 yedge = GetSystemMetrics(SM_CYEDGE); 971 /* swap for CCS_VERT? */ 972 } 973 974 /* compute rebar window rect in parent client coordinates */ 975 GetWindowRect(infoPtr->hwndSelf, &rcSelf); 976 MapWindowPoints(HWND_DESKTOP, GetParent(infoPtr->hwndSelf), (LPPOINT)&rcSelf, 2); 977 translate_rect(infoPtr, &rcSelf, &rcSelf); 978 979 height = infoPtr->calcSize.cy + 2*yedge; 980 if (!(infoPtr->dwStyle & CCS_NOPARENTALIGN)) { 981 RECT rcParent; 982 983 x = -xedge; 984 width = infoPtr->calcSize.cx + 2*xedge; 985 y = 0; /* quiet compiler warning */ 986 switch ( infoPtr->dwStyle & CCS_LAYOUT_MASK) { 987 case 0: /* shouldn't happen - see NCCreate */ 988 case CCS_TOP: 989 y = ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER) - yedge; 990 break; 991 case CCS_NOMOVEY: 992 y = rcSelf.top; 993 break; 994 case CCS_BOTTOM: 995 GetClientRect(GetParent(infoPtr->hwndSelf), &rcParent); 996 translate_rect(infoPtr, &rcParent, &rcParent); 997 y = rcParent.bottom - infoPtr->calcSize.cy - yedge; 998 break; 999 } 1000 } 1001 else { 1002 x = rcSelf.left; 1003 /* As on Windows if the CCS_NODIVIDER is not present the control will move 1004 * 2 pixel down after every layout */ 1005 y = rcSelf.top + ((infoPtr->dwStyle & CCS_NODIVIDER) ? 0 : REBAR_DIVIDER); 1006 width = rcSelf.right - rcSelf.left; 1007 } 1008 1009 TRACE("hwnd %p, style=%08x, setting at (%d,%d) for (%d,%d)\n", 1010 infoPtr->hwndSelf, infoPtr->dwStyle, x, y, width, height); 1011 1012 /* Set flag to ignore next WM_SIZE message and resize the window */ 1013 infoPtr->fStatus |= SELF_RESIZE; 1014 if ((infoPtr->dwStyle & CCS_VERT) == 0) 1015 SetWindowPos(infoPtr->hwndSelf, 0, x, y, width, height, SWP_NOZORDER); 1016 else 1017 SetWindowPos(infoPtr->hwndSelf, 0, y, x, height, width, SWP_NOZORDER); 1018 infoPtr->fStatus &= ~SELF_RESIZE; 1019 } 1020 1021 1022 static VOID 1023 REBAR_MoveChildWindows (const REBAR_INFO *infoPtr, UINT start, UINT endplus) 1024 { 1025 static const WCHAR strComboBox[] = { 'C','o','m','b','o','B','o','x',0 }; 1026 REBAR_BAND *lpBand; 1027 WCHAR szClassName[40]; 1028 UINT i; 1029 NMREBARCHILDSIZE rbcz; 1030 HDWP deferpos; 1031 1032 if (!(deferpos = BeginDeferWindowPos(infoPtr->uNumBands))) 1033 ERR("BeginDeferWindowPos returned NULL\n"); 1034 1035 for (i = start; i < endplus; i++) { 1036 lpBand = REBAR_GetBand(infoPtr, i); 1037 1038 if (HIDDENBAND(lpBand)) continue; 1039 if (lpBand->hwndChild) { 1040 TRACE("hwndChild = %p\n", lpBand->hwndChild); 1041 1042 /* Always generate the RBN_CHILDSIZE even if child 1043 did not change */ 1044 rbcz.uBand = i; 1045 rbcz.wID = lpBand->wID; 1046 rbcz.rcChild = lpBand->rcChild; 1047 translate_rect(infoPtr, &rbcz.rcBand, &lpBand->rcBand); 1048 if (infoPtr->dwStyle & CCS_VERT) 1049 rbcz.rcBand.top += lpBand->cxHeader; 1050 else 1051 rbcz.rcBand.left += lpBand->cxHeader; 1052 REBAR_Notify ((NMHDR *)&rbcz, infoPtr, RBN_CHILDSIZE); 1053 if (!EqualRect (&lpBand->rcChild, &rbcz.rcChild)) { 1054 TRACE("Child rect changed by NOTIFY for band %u\n", i); 1055 TRACE(" from (%s) to (%s)\n", 1056 wine_dbgstr_rect(&lpBand->rcChild), 1057 wine_dbgstr_rect(&rbcz.rcChild)); 1058 lpBand->rcChild = rbcz.rcChild; /* *** ??? */ 1059 } 1060 1061 GetClassNameW (lpBand->hwndChild, szClassName, ARRAY_SIZE(szClassName)); 1062 if (!lstrcmpW (szClassName, strComboBox) || 1063 !lstrcmpW (szClassName, WC_COMBOBOXEXW)) { 1064 INT nEditHeight, yPos; 1065 RECT rc; 1066 1067 /* special placement code for combo or comboex box */ 1068 1069 1070 /* get size of edit line */ 1071 GetWindowRect (lpBand->hwndChild, &rc); 1072 nEditHeight = rc.bottom - rc.top; 1073 yPos = (lpBand->rcChild.bottom + lpBand->rcChild.top - nEditHeight)/2; 1074 1075 /* center combo box inside child area */ 1076 TRACE("moving child (Combo(Ex)) %p to (%d,%d) for (%d,%d)\n", 1077 lpBand->hwndChild, 1078 lpBand->rcChild.left, yPos, 1079 lpBand->rcChild.right - lpBand->rcChild.left, 1080 nEditHeight); 1081 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, 1082 lpBand->rcChild.left, 1083 /*lpBand->rcChild.top*/ yPos, 1084 lpBand->rcChild.right - lpBand->rcChild.left, 1085 nEditHeight, 1086 SWP_NOZORDER); 1087 if (!deferpos) 1088 ERR("DeferWindowPos returned NULL\n"); 1089 } 1090 else { 1091 TRACE("moving child (Other) %p to (%d,%d) for (%d,%d)\n", 1092 lpBand->hwndChild, 1093 lpBand->rcChild.left, lpBand->rcChild.top, 1094 lpBand->rcChild.right - lpBand->rcChild.left, 1095 lpBand->rcChild.bottom - lpBand->rcChild.top); 1096 deferpos = DeferWindowPos (deferpos, lpBand->hwndChild, HWND_TOP, 1097 lpBand->rcChild.left, 1098 lpBand->rcChild.top, 1099 lpBand->rcChild.right - lpBand->rcChild.left, 1100 lpBand->rcChild.bottom - lpBand->rcChild.top, 1101 SWP_NOZORDER); 1102 if (!deferpos) 1103 ERR("DeferWindowPos returned NULL\n"); 1104 } 1105 } 1106 } 1107 if (!EndDeferWindowPos(deferpos)) 1108 ERR("EndDeferWindowPos returned NULL\n"); 1109 1110 if (infoPtr->DoRedraw) 1111 UpdateWindow (infoPtr->hwndSelf); 1112 } 1113 1114 /* Returns the next visible band (the first visible band in [i+1; infoPtr->uNumBands) ) 1115 * or infoPtr->uNumBands if none */ 1116 static int next_visible(const REBAR_INFO *infoPtr, int i) 1117 { 1118 unsigned int n; 1119 for (n = i + 1; n < infoPtr->uNumBands; n++) 1120 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n))) 1121 break; 1122 return n; 1123 } 1124 1125 /* Returns the previous visible band (the last visible band in [0; i) ) 1126 * or -1 if none */ 1127 static int prev_visible(const REBAR_INFO *infoPtr, int i) 1128 { 1129 int n; 1130 for (n = i - 1; n >= 0; n--) 1131 if (!HIDDENBAND(REBAR_GetBand(infoPtr, n))) 1132 break; 1133 return n; 1134 } 1135 1136 /* Returns the first visible band or infoPtr->uNumBands if none */ 1137 static int first_visible(const REBAR_INFO *infoPtr) 1138 { 1139 return next_visible(infoPtr, -1); /* this works*/ 1140 } 1141 1142 /* Returns the first visible band for the given row (or iBand if none) */ 1143 static int get_row_begin_for_band(const REBAR_INFO *infoPtr, INT iBand) 1144 { 1145 int iLastBand = iBand; 1146 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow; 1147 while ((iBand = prev_visible(infoPtr, iBand)) >= 0) { 1148 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow) 1149 break; 1150 else 1151 iLastBand = iBand; 1152 } 1153 return iLastBand; 1154 } 1155 1156 /* Returns the first visible band for the next row (or infoPtr->uNumBands if none) */ 1157 static int get_row_end_for_band(const REBAR_INFO *infoPtr, INT iBand) 1158 { 1159 int iRow = REBAR_GetBand(infoPtr, iBand)->iRow; 1160 while ((iBand = next_visible(infoPtr, iBand)) < infoPtr->uNumBands) 1161 if (REBAR_GetBand(infoPtr, iBand)->iRow != iRow) 1162 break; 1163 return iBand; 1164 } 1165 1166 /* Compute the rcBand.{left,right} from the cxEffective bands widths computed earlier. 1167 * iBeginBand must be visible */ 1168 static void REBAR_SetRowRectsX(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand) 1169 { 1170 int xPos = 0, i; 1171 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1172 { 1173 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 1174 if (lpBand->rcBand.left != xPos || lpBand->rcBand.right != xPos + lpBand->cxEffective) { 1175 lpBand->fDraw |= NTF_INVALIDATE; 1176 TRACE("Setting rect %d to %d,%d\n", i, xPos, xPos + lpBand->cxEffective); 1177 lpBand->rcBand.left = xPos; 1178 lpBand->rcBand.right = xPos + lpBand->cxEffective; 1179 } 1180 xPos += lpBand->cxEffective + SEP_WIDTH; 1181 } 1182 } 1183 1184 /* The rationale of this function is probably as follows: if we have some space 1185 * to distribute we want to add it to a band on the right. However we don't want 1186 * to unminimize a minimized band so we search for a band that is big enough. 1187 * For some reason "big enough" is defined as bigger than the minimum size of the 1188 * first band in the row 1189 */ 1190 static REBAR_BAND *REBAR_FindBandToGrow(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand) 1191 { 1192 INT cxMinFirstBand = 0, i; 1193 1194 cxMinFirstBand = REBAR_GetBand(infoPtr, iBeginBand)->cxMinBand; 1195 1196 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 1197 if (REBAR_GetBand(infoPtr, i)->cxEffective > cxMinFirstBand && 1198 !(REBAR_GetBand(infoPtr, i)->fStyle & RBBS_FIXEDSIZE)) 1199 break; 1200 1201 if (i < iBeginBand) 1202 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 1203 if (REBAR_GetBand(infoPtr, i)->cxMinBand == cxMinFirstBand) 1204 break; 1205 1206 TRACE("Extra space for row [%d..%d) should be added to band %d\n", iBeginBand, iEndBand, i); 1207 return REBAR_GetBand(infoPtr, i); 1208 } 1209 1210 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the right */ 1211 static int REBAR_ShrinkBandsRTL(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) 1212 { 1213 REBAR_BAND *lpBand; 1214 INT width, i; 1215 1216 TRACE("Shrinking bands [%d..%d) by %d, right-to-left\n", iBeginBand, iEndBand, cxShrink); 1217 for (i = prev_visible(infoPtr, iEndBand); i >= iBeginBand; i = prev_visible(infoPtr, i)) 1218 { 1219 lpBand = REBAR_GetBand(infoPtr, i); 1220 1221 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand); 1222 cxShrink -= lpBand->cxEffective - width; 1223 lpBand->cxEffective = width; 1224 if (bEnforce && lpBand->cx > lpBand->cxEffective) 1225 lpBand->cx = lpBand->cxEffective; 1226 if (cxShrink == 0) 1227 break; 1228 } 1229 return cxShrink; 1230 } 1231 1232 1233 /* Try to shrink the visible bands in [iBeginBand; iEndBand) by cxShrink, starting from the left. 1234 * iBeginBand must be visible */ 1235 static int REBAR_ShrinkBandsLTR(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT cxShrink, BOOL bEnforce) 1236 { 1237 REBAR_BAND *lpBand; 1238 INT width, i; 1239 1240 TRACE("Shrinking bands [%d..%d) by %d, left-to-right\n", iBeginBand, iEndBand, cxShrink); 1241 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1242 { 1243 lpBand = REBAR_GetBand(infoPtr, i); 1244 1245 width = max(lpBand->cxEffective - cxShrink, (int)lpBand->cxMinBand); 1246 cxShrink -= lpBand->cxEffective - width; 1247 lpBand->cxEffective = width; 1248 if (bEnforce) 1249 lpBand->cx = lpBand->cxEffective; 1250 if (cxShrink == 0) 1251 break; 1252 } 1253 return cxShrink; 1254 } 1255 1256 /* Tries to move a band to a given offset within a row. */ 1257 static int REBAR_MoveBandToRowOffset(REBAR_INFO *infoPtr, INT iBand, INT iFirstBand, 1258 INT iLastBand, INT xOff, BOOL reorder) 1259 { 1260 REBAR_BAND *insertBand = REBAR_GetBand(infoPtr, iBand); 1261 int xPos = 0, i; 1262 const BOOL setBreak = REBAR_GetBand(infoPtr, iFirstBand)->fStyle & RBBS_BREAK; 1263 1264 /* Find the band's new position */ 1265 if(reorder) 1266 { 1267 /* Used during an LR band reorder drag */ 1268 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i)) 1269 { 1270 if(xPos > xOff) 1271 break; 1272 xPos += REBAR_GetBand(infoPtr, i)->cxEffective + SEP_WIDTH; 1273 } 1274 } 1275 else 1276 { 1277 /* Used during a UD band insertion drag */ 1278 for (i = iFirstBand; i < iLastBand; i = next_visible(infoPtr, i)) 1279 { 1280 const REBAR_BAND *band = REBAR_GetBand(infoPtr, i); 1281 if(xPos + band->cxMinBand / 2 > xOff) 1282 break; 1283 xPos += band->cxEffective + SEP_WIDTH; 1284 } 1285 } 1286 1287 /* Move the band to its new position */ 1288 DPA_DeletePtr(infoPtr->bands, iBand); 1289 if(i > iBand) 1290 i--; 1291 DPA_InsertPtr(infoPtr->bands, i, insertBand); 1292 1293 /* Ensure only the last band has the RBBS_BREAK flag set */ 1294 insertBand->fStyle &= ~RBBS_BREAK; 1295 if(setBreak) 1296 REBAR_GetBand(infoPtr, iFirstBand)->fStyle |= RBBS_BREAK; 1297 1298 /* Return the currently grabbed band */ 1299 if(infoPtr->iGrabbedBand == iBand) 1300 { 1301 infoPtr->iGrabbedBand = i; 1302 return i; 1303 } 1304 else return -1; 1305 } 1306 1307 /* Set the heights of the visible bands in [iBeginBand; iEndBand) to the max height. iBeginBand must be visible */ 1308 static int REBAR_SetBandsHeight(const REBAR_INFO *infoPtr, INT iBeginBand, INT iEndBand, INT yStart) 1309 { 1310 REBAR_BAND *lpBand; 1311 int yMaxHeight = 0; 1312 int yPos = yStart; 1313 int row, i; 1314 1315 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1316 { 1317 lpBand = REBAR_GetBand(infoPtr, i); 1318 lpBand->cyRowSoFar = yMaxHeight; 1319 yMaxHeight = max(yMaxHeight, lpBand->cyMinBand); 1320 } 1321 TRACE("Bands [%d; %d) height: %d\n", iBeginBand, iEndBand, yMaxHeight); 1322 1323 row = iBeginBand < iEndBand ? REBAR_GetBand(infoPtr, iBeginBand)->iRow : 0; 1324 1325 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1326 { 1327 lpBand = REBAR_GetBand(infoPtr, i); 1328 /* we may be called for multiple rows if RBS_VARHEIGHT not set */ 1329 if (lpBand->iRow != row) { 1330 yPos += yMaxHeight + SEP_WIDTH; 1331 row = lpBand->iRow; 1332 } 1333 1334 if (lpBand->rcBand.top != yPos || lpBand->rcBand.bottom != yPos + yMaxHeight) { 1335 lpBand->fDraw |= NTF_INVALIDATE; 1336 lpBand->rcBand.top = yPos; 1337 lpBand->rcBand.bottom = yPos + yMaxHeight; 1338 TRACE("Band %d: %s\n", i, wine_dbgstr_rect(&lpBand->rcBand)); 1339 } 1340 } 1341 return yPos + yMaxHeight; 1342 } 1343 1344 /* Layout the row [iBeginBand; iEndBand). iBeginBand must be visible */ 1345 static void REBAR_LayoutRow(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int cx, int *piRow, int *pyPos) 1346 { 1347 REBAR_BAND *lpBand; 1348 int i, extra; 1349 int width = 0; 1350 1351 TRACE("Adjusting row [%d;%d). Width: %d\n", iBeginBand, iEndBand, cx); 1352 for (i = iBeginBand; i < iEndBand; i++) 1353 REBAR_GetBand(infoPtr, i)->iRow = *piRow; 1354 1355 /* compute the extra space */ 1356 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1357 { 1358 lpBand = REBAR_GetBand(infoPtr, i); 1359 if (i > iBeginBand) 1360 width += SEP_WIDTH; 1361 lpBand->cxEffective = max(lpBand->cxMinBand, lpBand->cx); 1362 width += lpBand->cxEffective; 1363 } 1364 1365 extra = cx - width; 1366 TRACE("Extra space: %d\n", extra); 1367 if (extra < 0) { 1368 int ret = REBAR_ShrinkBandsRTL(infoPtr, iBeginBand, iEndBand, -extra, FALSE); 1369 if (ret > 0 && next_visible(infoPtr, iBeginBand) != iEndBand) /* one band may be longer than expected... */ 1370 ERR("Error layouting row %d - couldn't shrink for %d pixels (%d total shrink)\n", *piRow, ret, -extra); 1371 } else 1372 if (extra > 0) { 1373 lpBand = REBAR_FindBandToGrow(infoPtr, iBeginBand, iEndBand); 1374 lpBand->cxEffective += extra; 1375 } 1376 1377 REBAR_SetRowRectsX(infoPtr, iBeginBand, iEndBand); 1378 if (infoPtr->dwStyle & RBS_VARHEIGHT) 1379 { 1380 if (*piRow > 0) 1381 *pyPos += SEP_WIDTH; 1382 *pyPos = REBAR_SetBandsHeight(infoPtr, iBeginBand, iEndBand, *pyPos); 1383 } 1384 (*piRow)++; 1385 } 1386 1387 static VOID 1388 REBAR_Layout(REBAR_INFO *infoPtr) 1389 { 1390 REBAR_BAND *lpBand; 1391 RECT rcAdj; 1392 SIZE oldSize; 1393 INT adjcx, i; 1394 INT rowstart; 1395 INT row = 0; 1396 INT xMin, yPos; 1397 1398 if (infoPtr->dwStyle & (CCS_NORESIZE | CCS_NOPARENTALIGN) || GetParent(infoPtr->hwndSelf) == NULL) 1399 GetClientRect(infoPtr->hwndSelf, &rcAdj); 1400 else 1401 GetClientRect(GetParent(infoPtr->hwndSelf), &rcAdj); 1402 TRACE("adjustment rect is (%s)\n", wine_dbgstr_rect(&rcAdj)); 1403 1404 adjcx = get_rect_cx(infoPtr, &rcAdj); 1405 1406 if (infoPtr->uNumBands == 0) { 1407 TRACE("No bands - setting size to (0,%d), style: %x\n", adjcx, infoPtr->dwStyle); 1408 infoPtr->calcSize.cx = adjcx; 1409 /* the calcSize.cy won't change for a 0 band rebar */ 1410 infoPtr->uNumRows = 0; 1411 REBAR_ForceResize(infoPtr); 1412 return; 1413 } 1414 1415 yPos = 0; 1416 xMin = 0; 1417 rowstart = first_visible(infoPtr); 1418 /* divide rows */ 1419 for (i = rowstart; i < infoPtr->uNumBands; i = next_visible(infoPtr, i)) 1420 { 1421 lpBand = REBAR_GetBand(infoPtr, i); 1422 1423 if (i > rowstart && (lpBand->fStyle & RBBS_BREAK || xMin + lpBand->cxMinBand > adjcx)) { 1424 TRACE("%s break on band %d\n", (lpBand->fStyle & RBBS_BREAK ? "Hard" : "Soft"), i - 1); 1425 REBAR_LayoutRow(infoPtr, rowstart, i, adjcx, &row, &yPos); 1426 rowstart = i; 1427 xMin = 0; 1428 } 1429 else 1430 xMin += SEP_WIDTH; 1431 1432 xMin += lpBand->cxMinBand; 1433 } 1434 if (rowstart < infoPtr->uNumBands) 1435 REBAR_LayoutRow(infoPtr, rowstart, infoPtr->uNumBands, adjcx, &row, &yPos); 1436 1437 if (!(infoPtr->dwStyle & RBS_VARHEIGHT)) 1438 yPos = REBAR_SetBandsHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, 0); 1439 1440 infoPtr->uNumRows = row; 1441 1442 if (infoPtr->dwStyle & CCS_VERT) 1443 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); 1444 else 1445 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands); 1446 /* now compute size of Rebar itself */ 1447 oldSize = infoPtr->calcSize; 1448 1449 infoPtr->calcSize.cx = adjcx; 1450 infoPtr->calcSize.cy = yPos; 1451 TRACE("calcsize size=(%d, %d), origheight=(%d,%d)\n", 1452 infoPtr->calcSize.cx, infoPtr->calcSize.cy, 1453 oldSize.cx, oldSize.cy); 1454 1455 REBAR_DumpBand (infoPtr); 1456 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); 1457 REBAR_ForceResize (infoPtr); 1458 1459 /* note: after a RBN_HEIGHTCHANGE native sends once again all the RBN_CHILDSIZE 1460 * and does another ForceResize */ 1461 if (oldSize.cy != infoPtr->calcSize.cy) 1462 { 1463 NMHDR heightchange; 1464 REBAR_Notify(&heightchange, infoPtr, RBN_HEIGHTCHANGE); 1465 REBAR_AutoSize(infoPtr, FALSE); 1466 } 1467 } 1468 1469 /* iBeginBand must be visible */ 1470 static int 1471 REBAR_SizeChildrenToHeight(const REBAR_INFO *infoPtr, int iBeginBand, int iEndBand, int extra, BOOL *fChanged) 1472 { 1473 int cyBandsOld; 1474 int cyBandsNew = 0; 1475 int i; 1476 1477 TRACE("[%d;%d) by %d\n", iBeginBand, iEndBand, extra); 1478 1479 cyBandsOld = REBAR_GetBand(infoPtr, iBeginBand)->rcBand.bottom - 1480 REBAR_GetBand(infoPtr, iBeginBand)->rcBand.top; 1481 for (i = iBeginBand; i < iEndBand; i = next_visible(infoPtr, i)) 1482 { 1483 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 1484 int cyMaxChild = cyBandsOld - REBARSPACE(lpBand) + extra; 1485 int cyChild = round_child_height(lpBand, cyMaxChild); 1486 1487 if (lpBand->hwndChild && cyChild != lpBand->cyChild && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) 1488 { 1489 TRACE("Resizing %d: %d -> %d [%d]\n", i, lpBand->cyChild, cyChild, lpBand->cyMaxChild); 1490 *fChanged = TRUE; 1491 lpBand->cyChild = cyChild; 1492 lpBand->fDraw |= NTF_INVALIDATE; 1493 update_min_band_height(infoPtr, lpBand); 1494 } 1495 cyBandsNew = max(cyBandsNew, lpBand->cyMinBand); 1496 } 1497 return cyBandsNew - cyBandsOld; 1498 } 1499 1500 /* worker function for RB_SIZETORECT and RBS_AUTOSIZE */ 1501 static VOID 1502 REBAR_SizeToHeight(REBAR_INFO *infoPtr, int height) 1503 { 1504 int extra = height - infoPtr->calcSize.cy; /* may be negative */ 1505 BOOL fChanged = FALSE; 1506 UINT uNumRows = infoPtr->uNumRows; 1507 int i; 1508 1509 if (uNumRows == 0) /* avoid division by 0 */ 1510 return; 1511 1512 /* That's not exactly what Windows does but should be similar */ 1513 1514 /* Pass one: break-up/glue rows */ 1515 if (extra > 0) 1516 { 1517 for (i = prev_visible(infoPtr, infoPtr->uNumBands); i > 0; i = prev_visible(infoPtr, i)) 1518 { 1519 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 1520 int cyBreakExtra; /* additional cy for the rebar after a RBBS_BREAK on this band */ 1521 1522 height = lpBand->rcBand.bottom - lpBand->rcBand.top; 1523 1524 if (infoPtr->dwStyle & RBS_VARHEIGHT) 1525 cyBreakExtra = lpBand->cyRowSoFar; /* 'height' => 'lpBand->cyRowSoFar' + 'height'*/ 1526 else 1527 cyBreakExtra = height; /* 'height' => 'height' + 'height'*/ 1528 cyBreakExtra += SEP_WIDTH; 1529 1530 if (extra <= cyBreakExtra / 2) 1531 break; 1532 1533 if (!(lpBand->fStyle & RBBS_BREAK)) 1534 { 1535 TRACE("Adding break on band %d - extra %d -> %d\n", i, extra, extra - cyBreakExtra); 1536 lpBand->fStyle |= RBBS_BREAK; 1537 lpBand->fDraw |= NTF_INVALIDATE; 1538 fChanged = TRUE; 1539 extra -= cyBreakExtra; 1540 uNumRows++; 1541 /* temporary change for _SizeControlsToHeight. The true values will be computed in _Layout */ 1542 if (infoPtr->dwStyle & RBS_VARHEIGHT) 1543 lpBand->rcBand.bottom = lpBand->rcBand.top + lpBand->cyMinBand; 1544 } 1545 } 1546 } 1547 /* TODO: else if (extra < 0) { try to remove some RBBS_BREAKs } */ 1548 1549 /* Pass two: increase/decrease control height */ 1550 if (infoPtr->dwStyle & RBS_VARHEIGHT) 1551 { 1552 int i = first_visible(infoPtr); 1553 int iRow = 0; 1554 while (i < infoPtr->uNumBands) 1555 { 1556 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, i); 1557 int extraForRow = extra / (int)(uNumRows - iRow); 1558 int rowEnd; 1559 1560 /* we can't use get_row_end_for_band as we might have added RBBS_BREAK in the first phase */ 1561 for (rowEnd = next_visible(infoPtr, i); rowEnd < infoPtr->uNumBands; rowEnd = next_visible(infoPtr, rowEnd)) 1562 if (REBAR_GetBand(infoPtr, rowEnd)->iRow != lpBand->iRow || 1563 REBAR_GetBand(infoPtr, rowEnd)->fStyle & RBBS_BREAK) 1564 break; 1565 1566 extra -= REBAR_SizeChildrenToHeight(infoPtr, i, rowEnd, extraForRow, &fChanged); 1567 TRACE("extra = %d\n", extra); 1568 i = rowEnd; 1569 iRow++; 1570 } 1571 } 1572 else 1573 REBAR_SizeChildrenToHeight(infoPtr, first_visible(infoPtr), infoPtr->uNumBands, extra / infoPtr->uNumRows, &fChanged); 1574 1575 if (fChanged) 1576 REBAR_Layout(infoPtr); 1577 } 1578 1579 static VOID 1580 REBAR_AutoSize(REBAR_INFO *infoPtr, BOOL needsLayout) 1581 { 1582 RECT rc, rcNew; 1583 NMRBAUTOSIZE autosize; 1584 1585 if (needsLayout) 1586 REBAR_Layout(infoPtr); 1587 GetClientRect(infoPtr->hwndSelf, &rc); 1588 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, &rc)); 1589 GetClientRect(infoPtr->hwndSelf, &rcNew); 1590 1591 GetClientRect(infoPtr->hwndSelf, &autosize.rcTarget); 1592 autosize.fChanged = EqualRect(&rc, &rcNew); 1593 autosize.rcTarget = rc; 1594 autosize.rcActual = rcNew; 1595 REBAR_Notify((NMHDR *)&autosize, infoPtr, RBN_AUTOSIZE); 1596 } 1597 1598 static VOID 1599 REBAR_ValidateBand (const REBAR_INFO *infoPtr, REBAR_BAND *lpBand) 1600 /* Function: This routine evaluates the band specs supplied */ 1601 /* by the user and updates the following 5 fields in */ 1602 /* the internal band structure: cxHeader, cyHeader, cxMinBand, cyMinBand, fStatus */ 1603 { 1604 UINT header=0; 1605 UINT textheight=0, imageheight = 0; 1606 UINT i, nonfixed; 1607 REBAR_BAND *tBand; 1608 1609 lpBand->fStatus = 0; 1610 lpBand->cxMinBand = 0; 1611 lpBand->cyMinBand = 0; 1612 1613 /* Data coming in from users into the cx... and cy... fields */ 1614 /* may be bad, just garbage, because the user never clears */ 1615 /* the fields. RB_{SET|INSERT}BAND{A|W} just passes the data */ 1616 /* along if the fields exist in the input area. Here we must */ 1617 /* determine if the data is valid. I have no idea how MS does */ 1618 /* the validation, but it does because the RB_GETBANDINFO */ 1619 /* returns a 0 when I know the sample program passed in an */ 1620 /* address. Here I will use the algorithm that if the value */ 1621 /* is greater than 65535 then it is bad and replace it with */ 1622 /* a zero. Feel free to improve the algorithm. - GA 12/2000 */ 1623 if (lpBand->cxMinChild > 65535) lpBand->cxMinChild = 0; 1624 if (lpBand->cyMinChild > 65535) lpBand->cyMinChild = 0; 1625 if (lpBand->cx > 65535) lpBand->cx = 0; 1626 if (lpBand->cyChild > 65535) lpBand->cyChild = 0; 1627 if (lpBand->cyIntegral > 65535) lpBand->cyIntegral = 0; 1628 if (lpBand->cxIdeal > 65535) lpBand->cxIdeal = 0; 1629 if (lpBand->cxHeader > 65535) lpBand->cxHeader = 0; 1630 1631 /* TODO : we could try return to the caller if a value changed so that */ 1632 /* a REBAR_Layout is needed. Till now the caller should call it */ 1633 /* it always (we should also check what native does) */ 1634 1635 /* Header is where the image, text and gripper exist */ 1636 /* in the band and precede the child window. */ 1637 1638 /* count number of non-FIXEDSIZE and non-Hidden bands */ 1639 nonfixed = 0; 1640 for (i=0; i<infoPtr->uNumBands; i++){ 1641 tBand = REBAR_GetBand(infoPtr, i); 1642 if (!HIDDENBAND(tBand) && !(tBand->fStyle & RBBS_FIXEDSIZE)) 1643 nonfixed++; 1644 } 1645 1646 /* calculate gripper rectangle */ 1647 if ( (!(lpBand->fStyle & RBBS_NOGRIPPER)) && 1648 ( (lpBand->fStyle & RBBS_GRIPPERALWAYS) || 1649 ( !(lpBand->fStyle & RBBS_FIXEDSIZE) && (nonfixed > 1))) 1650 ) { 1651 lpBand->fStatus |= HAS_GRIPPER; 1652 if (infoPtr->dwStyle & CCS_VERT) 1653 if (infoPtr->dwStyle & RBS_VERTICALGRIPPER) 1654 header += (GRIPPER_HEIGHT + REBAR_PRE_GRIPPER); 1655 else 1656 header += (GRIPPER_WIDTH + REBAR_PRE_GRIPPER); 1657 else 1658 header += (REBAR_PRE_GRIPPER + GRIPPER_WIDTH); 1659 /* Always have 4 pixels before anything else */ 1660 header += REBAR_ALWAYS_SPACE; 1661 } 1662 1663 /* image is visible */ 1664 if (lpBand->iImage != -1 && (infoPtr->himl)) { 1665 lpBand->fStatus |= HAS_IMAGE; 1666 if (infoPtr->dwStyle & CCS_VERT) { 1667 header += (infoPtr->imageSize.cy + REBAR_POST_IMAGE); 1668 imageheight = infoPtr->imageSize.cx + 4; 1669 } 1670 else { 1671 header += (infoPtr->imageSize.cx + REBAR_POST_IMAGE); 1672 imageheight = infoPtr->imageSize.cy + 4; 1673 } 1674 } 1675 1676 /* text is visible */ 1677 if ((lpBand->fMask & RBBIM_TEXT) && (lpBand->lpText) && 1678 !(lpBand->fStyle & RBBS_HIDETITLE)) { 1679 HDC hdc = GetDC (0); 1680 HFONT hOldFont = SelectObject (hdc, infoPtr->hFont); 1681 SIZE size; 1682 1683 lpBand->fStatus |= HAS_TEXT; 1684 GetTextExtentPoint32W (hdc, lpBand->lpText, 1685 lstrlenW (lpBand->lpText), &size); 1686 header += ((infoPtr->dwStyle & CCS_VERT) ? (size.cy + REBAR_POST_TEXT) : (size.cx + REBAR_POST_TEXT)); 1687 textheight = (infoPtr->dwStyle & CCS_VERT) ? 0 : size.cy; 1688 1689 SelectObject (hdc, hOldFont); 1690 ReleaseDC (0, hdc); 1691 } 1692 1693 /* if no gripper but either image or text, then leave space */ 1694 if ((lpBand->fStatus & (HAS_IMAGE | HAS_TEXT)) && 1695 !(lpBand->fStatus & HAS_GRIPPER)) { 1696 header += REBAR_ALWAYS_SPACE; 1697 } 1698 1699 /* check if user overrode the header value */ 1700 if (!(lpBand->fStyle & RBBS_UNDOC_FIXEDHEADER)) 1701 lpBand->cxHeader = header; 1702 lpBand->cyHeader = max(textheight, imageheight); 1703 1704 /* Now compute minimum size of child window */ 1705 update_min_band_height(infoPtr, lpBand); /* update lpBand->cyMinBand from cyHeader and cyChild*/ 1706 1707 lpBand->cxMinBand = lpBand->cxMinChild + lpBand->cxHeader + REBAR_POST_CHILD; 1708 if (lpBand->fStyle & RBBS_USECHEVRON && lpBand->cxMinChild < lpBand->cxIdeal) 1709 lpBand->cxMinBand += CHEVRON_WIDTH; 1710 } 1711 1712 static UINT 1713 REBAR_CommonSetupBand(HWND hwnd, const REBARBANDINFOW *lprbbi, REBAR_BAND *lpBand) 1714 /* Function: This routine copies the supplied values from */ 1715 /* user input (lprbbi) to the internal band structure. */ 1716 /* It returns the mask of what changed. */ 1717 { 1718 UINT uChanged = 0x0; 1719 1720 lpBand->fMask |= lprbbi->fMask; 1721 1722 if( (lprbbi->fMask & RBBIM_STYLE) && 1723 (lpBand->fStyle != lprbbi->fStyle ) ) 1724 { 1725 lpBand->fStyle = lprbbi->fStyle; 1726 uChanged |= RBBIM_STYLE; 1727 } 1728 1729 if( (lprbbi->fMask & RBBIM_COLORS) && 1730 ( ( lpBand->clrFore != lprbbi->clrFore ) || 1731 ( lpBand->clrBack != lprbbi->clrBack ) ) ) 1732 { 1733 lpBand->clrFore = lprbbi->clrFore; 1734 lpBand->clrBack = lprbbi->clrBack; 1735 uChanged |= RBBIM_COLORS; 1736 } 1737 1738 if( (lprbbi->fMask & RBBIM_IMAGE) && 1739 ( lpBand->iImage != lprbbi->iImage ) ) 1740 { 1741 lpBand->iImage = lprbbi->iImage; 1742 uChanged |= RBBIM_IMAGE; 1743 } 1744 1745 if( (lprbbi->fMask & RBBIM_CHILD) && 1746 (lprbbi->hwndChild != lpBand->hwndChild ) ) 1747 { 1748 if (lprbbi->hwndChild) { 1749 lpBand->hwndChild = lprbbi->hwndChild; 1750 lpBand->hwndPrevParent = 1751 SetParent (lpBand->hwndChild, hwnd); 1752 /* below in trace from WinRAR */ 1753 ShowWindow(lpBand->hwndChild, SW_SHOWNOACTIVATE | SW_SHOWNORMAL); 1754 /* above in trace from WinRAR */ 1755 } 1756 else { 1757 TRACE("child: %p prev parent: %p\n", 1758 lpBand->hwndChild, lpBand->hwndPrevParent); 1759 lpBand->hwndChild = 0; 1760 lpBand->hwndPrevParent = 0; 1761 } 1762 uChanged |= RBBIM_CHILD; 1763 } 1764 1765 if( (lprbbi->fMask & RBBIM_CHILDSIZE) && 1766 ( (lpBand->cxMinChild != lprbbi->cxMinChild) || 1767 (lpBand->cyMinChild != lprbbi->cyMinChild ) || 1768 ( (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) && 1769 ( (lpBand->cyChild != lprbbi->cyChild ) || 1770 (lpBand->cyMaxChild != lprbbi->cyMaxChild ) || 1771 (lpBand->cyIntegral != lprbbi->cyIntegral ) ) ) || 1772 ( (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE) && 1773 ( (lpBand->cyChild || 1774 lpBand->cyMaxChild || 1775 lpBand->cyIntegral ) ) ) ) ) 1776 { 1777 lpBand->cxMinChild = lprbbi->cxMinChild; 1778 lpBand->cyMinChild = lprbbi->cyMinChild; 1779 /* These fields where added in WIN32_IE == 0x400 and are set only for RBBS_VARIABLEHEIGHT bands */ 1780 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 1781 lpBand->cyMaxChild = lprbbi->cyMaxChild; 1782 lpBand->cyIntegral = lprbbi->cyIntegral; 1783 1784 lpBand->cyChild = round_child_height(lpBand, lprbbi->cyChild); /* make (cyChild - cyMinChild) a multiple of cyIntergral */ 1785 } 1786 else { 1787 lpBand->cyChild = lpBand->cyMinChild; 1788 lpBand->cyMaxChild = 0x7fffffff; 1789 lpBand->cyIntegral = 0; 1790 } 1791 uChanged |= RBBIM_CHILDSIZE; 1792 } 1793 1794 if( (lprbbi->fMask & RBBIM_SIZE) && 1795 (lpBand->cx != lprbbi->cx ) ) 1796 { 1797 lpBand->cx = lprbbi->cx; 1798 uChanged |= RBBIM_SIZE; 1799 } 1800 1801 if( (lprbbi->fMask & RBBIM_BACKGROUND) && 1802 ( lpBand->hbmBack != lprbbi->hbmBack ) ) 1803 { 1804 lpBand->hbmBack = lprbbi->hbmBack; 1805 uChanged |= RBBIM_BACKGROUND; 1806 } 1807 1808 if( (lprbbi->fMask & RBBIM_ID) && 1809 (lpBand->wID != lprbbi->wID ) ) 1810 { 1811 lpBand->wID = lprbbi->wID; 1812 uChanged |= RBBIM_ID; 1813 } 1814 1815 /* check for additional data */ 1816 if (lprbbi->cbSize >= REBARBANDINFOA_V6_SIZE) { 1817 if( (lprbbi->fMask & RBBIM_IDEALSIZE) && 1818 ( lpBand->cxIdeal != lprbbi->cxIdeal ) ) 1819 { 1820 lpBand->cxIdeal = lprbbi->cxIdeal; 1821 uChanged |= RBBIM_IDEALSIZE; 1822 } 1823 1824 if( (lprbbi->fMask & RBBIM_LPARAM) && 1825 (lpBand->lParam != lprbbi->lParam ) ) 1826 { 1827 lpBand->lParam = lprbbi->lParam; 1828 uChanged |= RBBIM_LPARAM; 1829 } 1830 1831 if( (lprbbi->fMask & RBBIM_HEADERSIZE) && 1832 (lpBand->cxHeader != lprbbi->cxHeader ) ) 1833 { 1834 lpBand->cxHeader = lprbbi->cxHeader; 1835 lpBand->fStyle |= RBBS_UNDOC_FIXEDHEADER; 1836 uChanged |= RBBIM_HEADERSIZE; 1837 } 1838 } 1839 1840 return uChanged; 1841 } 1842 1843 static LRESULT REBAR_EraseBkGnd (const REBAR_INFO *infoPtr, HDC hdc) 1844 /* Function: This erases the background rectangle by drawing */ 1845 /* each band with its background color (or the default) and */ 1846 /* draws each bands right separator if necessary. The row */ 1847 /* separators are drawn on the first band of the next row. */ 1848 { 1849 REBAR_BAND *lpBand; 1850 UINT i; 1851 INT oldrow; 1852 RECT cr; 1853 COLORREF old = CLR_NONE, new; 1854 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 1855 1856 GetClientRect (infoPtr->hwndSelf, &cr); 1857 1858 #ifdef __REACTOS__ 1859 if (theme) 1860 { 1861 if (IsThemeBackgroundPartiallyTransparent(theme, 0, 0)) 1862 { 1863 DrawThemeParentBackground (infoPtr->hwndSelf, hdc, &cr); 1864 } 1865 DrawThemeBackground (theme, hdc, 0, 0, &cr, NULL); 1866 } 1867 #endif 1868 1869 oldrow = -1; 1870 for(i=0; i<infoPtr->uNumBands; i++) { 1871 RECT rcBand; 1872 lpBand = REBAR_GetBand(infoPtr, i); 1873 if (HIDDENBAND(lpBand)) continue; 1874 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 1875 1876 /* draw band separator between rows */ 1877 if (lpBand->iRow != oldrow) { 1878 oldrow = lpBand->iRow; 1879 if (infoPtr->dwStyle & RBS_BANDBORDERS) { 1880 RECT rcRowSep; 1881 rcRowSep = rcBand; 1882 if (infoPtr->dwStyle & CCS_VERT) { 1883 rcRowSep.right += SEP_WIDTH_SIZE; 1884 rcRowSep.bottom = infoPtr->calcSize.cx; 1885 if (theme) 1886 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_RIGHT, NULL); 1887 else 1888 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_RIGHT); 1889 } 1890 else { 1891 rcRowSep.bottom += SEP_WIDTH_SIZE; 1892 rcRowSep.right = infoPtr->calcSize.cx; 1893 if (theme) 1894 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcRowSep, EDGE_ETCHED, BF_BOTTOM, NULL); 1895 else 1896 DrawEdge (hdc, &rcRowSep, EDGE_ETCHED, BF_BOTTOM); 1897 } 1898 TRACE ("drawing band separator bottom (%s)\n", 1899 wine_dbgstr_rect(&rcRowSep)); 1900 } 1901 } 1902 1903 /* draw band separator between bands in a row */ 1904 if (infoPtr->dwStyle & RBS_BANDBORDERS && lpBand->rcBand.left > 0) { 1905 RECT rcSep; 1906 rcSep = rcBand; 1907 if (infoPtr->dwStyle & CCS_VERT) { 1908 rcSep.bottom = rcSep.top; 1909 rcSep.top -= SEP_WIDTH_SIZE; 1910 if (theme) 1911 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_BOTTOM, NULL); 1912 else 1913 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_BOTTOM); 1914 } 1915 else { 1916 rcSep.right = rcSep.left; 1917 rcSep.left -= SEP_WIDTH_SIZE; 1918 if (theme) 1919 DrawThemeEdge (theme, hdc, RP_BAND, 0, &rcSep, EDGE_ETCHED, BF_RIGHT, NULL); 1920 else 1921 DrawEdge (hdc, &rcSep, EDGE_ETCHED, BF_RIGHT); 1922 } 1923 TRACE("drawing band separator right (%s)\n", 1924 wine_dbgstr_rect(&rcSep)); 1925 } 1926 1927 /* draw the actual background */ 1928 if (lpBand->clrBack != CLR_NONE) { 1929 new = (lpBand->clrBack == CLR_DEFAULT) ? infoPtr->clrBtnFace : 1930 lpBand->clrBack; 1931 #if GLATESTING 1932 /* testing only - make background green to see it */ 1933 new = RGB(0,128,0); 1934 #endif 1935 } 1936 else { 1937 /* In the absence of documentation for Rebar vs. CLR_NONE, 1938 * we will use the default BtnFace color. Note documentation 1939 * exists for Listview and Imagelist. 1940 */ 1941 new = infoPtr->clrBtnFace; 1942 #if GLATESTING 1943 /* testing only - make background green to see it */ 1944 new = RGB(0,128,0); 1945 #endif 1946 } 1947 1948 if (theme) 1949 { 1950 /* When themed, the background color is ignored (but not a 1951 * background bitmap */ 1952 DrawThemeBackground (theme, hdc, 0, 0, &cr, &rcBand); 1953 } 1954 else 1955 { 1956 old = SetBkColor (hdc, new); 1957 TRACE("%s background color=0x%06x, band %s\n", 1958 (lpBand->clrBack == CLR_NONE) ? "none" : 1959 ((lpBand->clrBack == CLR_DEFAULT) ? "dft" : ""), 1960 GetBkColor(hdc), wine_dbgstr_rect(&rcBand)); 1961 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &rcBand, NULL, 0, 0); 1962 if (lpBand->clrBack != CLR_NONE) 1963 SetBkColor (hdc, old); 1964 } 1965 } 1966 return TRUE; 1967 } 1968 1969 static void 1970 REBAR_InternalHitTest (const REBAR_INFO *infoPtr, const POINT *lpPt, UINT *pFlags, INT *pBand) 1971 { 1972 REBAR_BAND *lpBand; 1973 RECT rect; 1974 UINT iCount; 1975 1976 GetClientRect (infoPtr->hwndSelf, &rect); 1977 1978 *pFlags = RBHT_NOWHERE; 1979 if (PtInRect (&rect, *lpPt)) 1980 { 1981 if (infoPtr->uNumBands == 0) { 1982 *pFlags = RBHT_NOWHERE; 1983 if (pBand) 1984 *pBand = -1; 1985 TRACE("NOWHERE\n"); 1986 return; 1987 } 1988 else { 1989 /* somewhere inside */ 1990 for (iCount = 0; iCount < infoPtr->uNumBands; iCount++) { 1991 RECT rcBand; 1992 lpBand = REBAR_GetBand(infoPtr, iCount); 1993 translate_rect(infoPtr, &rcBand, &lpBand->rcBand); 1994 if (HIDDENBAND(lpBand)) continue; 1995 if (PtInRect (&rcBand, *lpPt)) { 1996 if (pBand) 1997 *pBand = iCount; 1998 if (PtInRect (&lpBand->rcGripper, *lpPt)) { 1999 *pFlags = RBHT_GRABBER; 2000 TRACE("ON GRABBER %d\n", iCount); 2001 return; 2002 } 2003 else if (PtInRect (&lpBand->rcCapImage, *lpPt)) { 2004 *pFlags = RBHT_CAPTION; 2005 TRACE("ON CAPTION %d\n", iCount); 2006 return; 2007 } 2008 else if (PtInRect (&lpBand->rcCapText, *lpPt)) { 2009 *pFlags = RBHT_CAPTION; 2010 TRACE("ON CAPTION %d\n", iCount); 2011 return; 2012 } 2013 else if (PtInRect (&lpBand->rcChild, *lpPt)) { 2014 *pFlags = RBHT_CLIENT; 2015 TRACE("ON CLIENT %d\n", iCount); 2016 return; 2017 } 2018 else if (PtInRect (&lpBand->rcChevron, *lpPt)) { 2019 *pFlags = RBHT_CHEVRON; 2020 TRACE("ON CHEVRON %d\n", iCount); 2021 return; 2022 } 2023 else { 2024 *pFlags = RBHT_NOWHERE; 2025 TRACE("NOWHERE %d\n", iCount); 2026 return; 2027 } 2028 } 2029 } 2030 2031 *pFlags = RBHT_NOWHERE; 2032 if (pBand) 2033 *pBand = -1; 2034 2035 TRACE("NOWHERE\n"); 2036 return; 2037 } 2038 } 2039 else { 2040 *pFlags = RBHT_NOWHERE; 2041 if (pBand) 2042 *pBand = -1; 2043 TRACE("NOWHERE\n"); 2044 return; 2045 } 2046 } 2047 2048 static void 2049 REBAR_HandleLRDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) 2050 /* Function: This will implement the functionality of a */ 2051 /* Gripper drag within a row. It will not implement "out- */ 2052 /* of-row" drags. (They are detected and handled in */ 2053 /* REBAR_MouseMove.) */ 2054 { 2055 REBAR_BAND *hitBand; 2056 INT iHitBand, iRowBegin, iRowEnd; 2057 INT movement, xBand, cxLeft = 0; 2058 BOOL shrunkBands = FALSE; 2059 2060 iHitBand = infoPtr->iGrabbedBand; 2061 iRowBegin = get_row_begin_for_band(infoPtr, iHitBand); 2062 iRowEnd = get_row_end_for_band(infoPtr, iHitBand); 2063 hitBand = REBAR_GetBand(infoPtr, iHitBand); 2064 2065 xBand = hitBand->rcBand.left; 2066 movement = (infoPtr->dwStyle&CCS_VERT ? ptsmove->y : ptsmove->x) 2067 - (xBand + REBAR_PRE_GRIPPER - infoPtr->ihitoffset); 2068 2069 /* Dragging the first band in a row cannot cause shrinking */ 2070 if(iHitBand != iRowBegin) 2071 { 2072 if (movement < 0) { 2073 cxLeft = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iHitBand, -movement, TRUE); 2074 2075 if(cxLeft < -movement) 2076 { 2077 hitBand->cxEffective += -movement - cxLeft; 2078 hitBand->cx = hitBand->cxEffective; 2079 shrunkBands = TRUE; 2080 } 2081 2082 } else if (movement > 0) { 2083 2084 cxLeft = movement; 2085 if (prev_visible(infoPtr, iHitBand) >= 0) 2086 cxLeft = REBAR_ShrinkBandsLTR(infoPtr, iHitBand, iRowEnd, movement, TRUE); 2087 2088 if(cxLeft < movement) 2089 { 2090 REBAR_BAND *lpPrev = REBAR_GetBand(infoPtr, prev_visible(infoPtr, iHitBand)); 2091 lpPrev->cxEffective += movement - cxLeft; 2092 lpPrev->cx = hitBand->cxEffective; 2093 shrunkBands = TRUE; 2094 } 2095 2096 } 2097 } 2098 2099 if(!shrunkBands) 2100 { 2101 /* It was not possible to move the band by shrinking bands. 2102 * Try relocating the band instead. */ 2103 REBAR_MoveBandToRowOffset(infoPtr, iHitBand, iRowBegin, 2104 iRowEnd, xBand + movement, TRUE); 2105 } 2106 2107 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 2108 if (infoPtr->dwStyle & CCS_VERT) 2109 REBAR_CalcVertBand(infoPtr, 0, infoPtr->uNumBands); 2110 else 2111 REBAR_CalcHorzBand(infoPtr, 0, infoPtr->uNumBands); 2112 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 2113 } 2114 2115 static void 2116 REBAR_HandleUDDrag (REBAR_INFO *infoPtr, const POINT *ptsmove) 2117 { 2118 INT yOff = (infoPtr->dwStyle & CCS_VERT) ? ptsmove->x : ptsmove->y; 2119 INT iHitBand, iRowBegin, iNextRowBegin; 2120 REBAR_BAND *hitBand, *rowBeginBand; 2121 2122 if(infoPtr->uNumBands <= 0) 2123 ERR("There are no bands in this rebar\n"); 2124 2125 /* Up/down dragging can only occur when there is more than one 2126 * band in the rebar */ 2127 if(infoPtr->uNumBands <= 1) 2128 return; 2129 2130 iHitBand = infoPtr->iGrabbedBand; 2131 hitBand = REBAR_GetBand(infoPtr, iHitBand); 2132 2133 /* If we're taking a band that has the RBBS_BREAK style set, this 2134 * style needs to be reapplied to the band that is going to become 2135 * the new start of the row. */ 2136 if((hitBand->fStyle & RBBS_BREAK) && 2137 (iHitBand < infoPtr->uNumBands - 1)) 2138 REBAR_GetBand(infoPtr, iHitBand + 1)->fStyle |= RBBS_BREAK; 2139 2140 if(yOff < 0) 2141 { 2142 /* Place the band above the current top row */ 2143 if(iHitBand==0 && (infoPtr->uNumBands==1 || REBAR_GetBand(infoPtr, 1)->fStyle&RBBS_BREAK)) 2144 return; 2145 DPA_DeletePtr(infoPtr->bands, iHitBand); 2146 hitBand->fStyle &= ~RBBS_BREAK; 2147 REBAR_GetBand(infoPtr, 0)->fStyle |= RBBS_BREAK; 2148 infoPtr->iGrabbedBand = DPA_InsertPtr( 2149 infoPtr->bands, 0, hitBand); 2150 } 2151 else if(yOff > REBAR_GetBand(infoPtr, infoPtr->uNumBands - 1)->rcBand.bottom) 2152 { 2153 /* Place the band below the current bottom row */ 2154 if(iHitBand == infoPtr->uNumBands-1 && hitBand->fStyle&RBBS_BREAK) 2155 return; 2156 DPA_DeletePtr(infoPtr->bands, iHitBand); 2157 hitBand->fStyle |= RBBS_BREAK; 2158 infoPtr->iGrabbedBand = DPA_InsertPtr( 2159 infoPtr->bands, infoPtr->uNumBands - 1, hitBand); 2160 } 2161 else 2162 { 2163 /* Place the band in the preexisting row the mouse is hovering over */ 2164 iRowBegin = first_visible(infoPtr); 2165 while(iRowBegin < infoPtr->uNumBands) 2166 { 2167 iNextRowBegin = get_row_end_for_band(infoPtr, iRowBegin); 2168 rowBeginBand = REBAR_GetBand(infoPtr, iRowBegin); 2169 if(rowBeginBand->rcBand.bottom > yOff) 2170 { 2171 REBAR_MoveBandToRowOffset( 2172 infoPtr, iHitBand, iRowBegin, iNextRowBegin, 2173 ((infoPtr->dwStyle & CCS_VERT) ? ptsmove->y : ptsmove->x) 2174 - REBAR_PRE_GRIPPER - infoPtr->ihitoffset, FALSE); 2175 break; 2176 } 2177 2178 iRowBegin = iNextRowBegin; 2179 } 2180 } 2181 2182 REBAR_Layout(infoPtr); 2183 } 2184 2185 2186 /* << REBAR_BeginDrag >> */ 2187 2188 2189 static LRESULT 2190 REBAR_DeleteBand (REBAR_INFO *infoPtr, WPARAM wParam) 2191 { 2192 UINT uBand = (UINT)wParam; 2193 REBAR_BAND *lpBand; 2194 2195 if (uBand >= infoPtr->uNumBands) 2196 return FALSE; 2197 2198 TRACE("deleting band %u!\n", uBand); 2199 lpBand = REBAR_GetBand(infoPtr, uBand); 2200 REBAR_Notify_NMREBAR (infoPtr, uBand, RBN_DELETINGBAND); 2201 /* TODO: a return of 1 should probably cancel the deletion */ 2202 2203 if (lpBand->hwndChild) 2204 ShowWindow(lpBand->hwndChild, SW_HIDE); 2205 Free(lpBand->lpText); 2206 Free(lpBand); 2207 2208 infoPtr->uNumBands--; 2209 DPA_DeletePtr(infoPtr->bands, uBand); 2210 2211 REBAR_Notify_NMREBAR (infoPtr, -1, RBN_DELETEDBAND); 2212 2213 /* if only 1 band left the re-validate to possible eliminate gripper */ 2214 if (infoPtr->uNumBands == 1) 2215 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0)); 2216 2217 REBAR_Layout(infoPtr); 2218 2219 return TRUE; 2220 } 2221 2222 2223 /* << REBAR_DragMove >> */ 2224 /* << REBAR_EndDrag >> */ 2225 2226 2227 static LRESULT 2228 REBAR_GetBandBorders (const REBAR_INFO *infoPtr, UINT uBand, RECT *lpRect) 2229 { 2230 REBAR_BAND *lpBand; 2231 2232 if (!lpRect) 2233 return 0; 2234 if (uBand >= infoPtr->uNumBands) 2235 return 0; 2236 2237 lpBand = REBAR_GetBand(infoPtr, uBand); 2238 2239 /* FIXME - the following values were determined by experimentation */ 2240 /* with the REBAR Control Spy. I have guesses as to what the 4 and */ 2241 /* 1 are, but I am not sure. There doesn't seem to be any actual */ 2242 /* difference in size of the control area with and without the */ 2243 /* style. - GA */ 2244 if (infoPtr->dwStyle & RBS_BANDBORDERS) { 2245 if (infoPtr->dwStyle & CCS_VERT) { 2246 lpRect->left = 1; 2247 lpRect->top = lpBand->cxHeader + 4; 2248 lpRect->right = 1; 2249 lpRect->bottom = 0; 2250 } 2251 else { 2252 lpRect->left = lpBand->cxHeader + 4; 2253 lpRect->top = 1; 2254 lpRect->right = 0; 2255 lpRect->bottom = 1; 2256 } 2257 } 2258 else { 2259 lpRect->left = lpBand->cxHeader; 2260 } 2261 return 0; 2262 } 2263 2264 2265 static inline LRESULT 2266 REBAR_GetBandCount (const REBAR_INFO *infoPtr) 2267 { 2268 TRACE("band count %u!\n", infoPtr->uNumBands); 2269 2270 return infoPtr->uNumBands; 2271 } 2272 2273 2274 static LRESULT 2275 REBAR_GetBandInfoT(const REBAR_INFO *infoPtr, UINT uIndex, LPREBARBANDINFOW lprbbi, BOOL bUnicode) 2276 { 2277 REBAR_BAND *lpBand; 2278 2279 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 2280 return FALSE; 2281 2282 if (uIndex >= infoPtr->uNumBands) 2283 return FALSE; 2284 2285 TRACE("index %u (bUnicode=%d)\n", uIndex, bUnicode); 2286 2287 /* copy band information */ 2288 lpBand = REBAR_GetBand(infoPtr, uIndex); 2289 2290 if (lprbbi->fMask & RBBIM_STYLE) 2291 lprbbi->fStyle = lpBand->fStyle; 2292 2293 if (lprbbi->fMask & RBBIM_COLORS) { 2294 lprbbi->clrFore = lpBand->clrFore; 2295 lprbbi->clrBack = lpBand->clrBack; 2296 if (lprbbi->clrBack == CLR_DEFAULT) 2297 lprbbi->clrBack = infoPtr->clrBtnFace; 2298 } 2299 2300 if (lprbbi->fMask & RBBIM_TEXT) { 2301 if (bUnicode) 2302 Str_GetPtrW(lpBand->lpText, lprbbi->lpText, lprbbi->cch); 2303 else 2304 Str_GetPtrWtoA(lpBand->lpText, (LPSTR)lprbbi->lpText, lprbbi->cch); 2305 } 2306 2307 if (lprbbi->fMask & RBBIM_IMAGE) 2308 lprbbi->iImage = lpBand->iImage; 2309 2310 if (lprbbi->fMask & RBBIM_CHILD) 2311 lprbbi->hwndChild = lpBand->hwndChild; 2312 2313 if (lprbbi->fMask & RBBIM_CHILDSIZE) { 2314 lprbbi->cxMinChild = lpBand->cxMinChild; 2315 lprbbi->cyMinChild = lpBand->cyMinChild; 2316 /* to make tests pass we follow Windows' behaviour and allow reading these fields only 2317 * for RBBS_VARIABLEHEIGHTS bands */ 2318 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE && (lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 2319 lprbbi->cyChild = lpBand->cyChild; 2320 lprbbi->cyMaxChild = lpBand->cyMaxChild; 2321 lprbbi->cyIntegral = lpBand->cyIntegral; 2322 } 2323 } 2324 2325 if (lprbbi->fMask & RBBIM_SIZE) 2326 lprbbi->cx = lpBand->cx; 2327 2328 if (lprbbi->fMask & RBBIM_BACKGROUND) 2329 lprbbi->hbmBack = lpBand->hbmBack; 2330 2331 if (lprbbi->fMask & RBBIM_ID) 2332 lprbbi->wID = lpBand->wID; 2333 2334 /* check for additional data */ 2335 if (lprbbi->cbSize >= REBARBANDINFOW_V6_SIZE) { 2336 if (lprbbi->fMask & RBBIM_IDEALSIZE) 2337 lprbbi->cxIdeal = lpBand->cxIdeal; 2338 2339 if (lprbbi->fMask & RBBIM_LPARAM) 2340 lprbbi->lParam = lpBand->lParam; 2341 2342 if (lprbbi->fMask & RBBIM_HEADERSIZE) 2343 lprbbi->cxHeader = lpBand->cxHeader; 2344 } 2345 2346 REBAR_DumpBandInfo(lprbbi); 2347 2348 return TRUE; 2349 } 2350 2351 2352 static LRESULT 2353 REBAR_GetBarHeight (const REBAR_INFO *infoPtr) 2354 { 2355 INT nHeight; 2356 2357 nHeight = infoPtr->calcSize.cy; 2358 2359 TRACE("height = %d\n", nHeight); 2360 2361 return nHeight; 2362 } 2363 2364 2365 static LRESULT 2366 REBAR_GetBarInfo (const REBAR_INFO *infoPtr, LPREBARINFO lpInfo) 2367 { 2368 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO)) 2369 return FALSE; 2370 2371 TRACE("getting bar info!\n"); 2372 2373 if (infoPtr->himl) { 2374 lpInfo->himl = infoPtr->himl; 2375 lpInfo->fMask |= RBIM_IMAGELIST; 2376 } 2377 2378 return TRUE; 2379 } 2380 2381 2382 static inline LRESULT 2383 REBAR_GetBkColor (const REBAR_INFO *infoPtr) 2384 { 2385 COLORREF clr = infoPtr->clrBk; 2386 2387 if (clr == CLR_DEFAULT) 2388 clr = infoPtr->clrBtnFace; 2389 2390 TRACE("background color 0x%06x!\n", clr); 2391 2392 return clr; 2393 } 2394 2395 2396 /* << REBAR_GetColorScheme >> */ 2397 /* << REBAR_GetDropTarget >> */ 2398 2399 2400 static LRESULT 2401 REBAR_GetPalette (const REBAR_INFO *infoPtr) 2402 { 2403 FIXME("empty stub!\n"); 2404 2405 return 0; 2406 } 2407 2408 2409 static LRESULT 2410 REBAR_GetRect (const REBAR_INFO *infoPtr, INT iBand, RECT *lprc) 2411 { 2412 REBAR_BAND *lpBand; 2413 2414 if (iBand < 0 || iBand >= infoPtr->uNumBands) 2415 return FALSE; 2416 if (!lprc) 2417 return FALSE; 2418 2419 lpBand = REBAR_GetBand(infoPtr, iBand); 2420 /* For CCS_VERT the coordinates will be swapped - like on Windows */ 2421 *lprc = lpBand->rcBand; 2422 2423 TRACE("band %d, (%s)\n", iBand, wine_dbgstr_rect(lprc)); 2424 2425 return TRUE; 2426 } 2427 2428 2429 static inline LRESULT 2430 REBAR_GetRowCount (const REBAR_INFO *infoPtr) 2431 { 2432 TRACE("%u\n", infoPtr->uNumRows); 2433 2434 return infoPtr->uNumRows; 2435 } 2436 2437 2438 static LRESULT 2439 REBAR_GetRowHeight (const REBAR_INFO *infoPtr, INT iRow) 2440 { 2441 int j = 0, ret = 0; 2442 UINT i; 2443 REBAR_BAND *lpBand; 2444 2445 for (i=0; i<infoPtr->uNumBands; i++) { 2446 lpBand = REBAR_GetBand(infoPtr, i); 2447 if (HIDDENBAND(lpBand)) continue; 2448 if (lpBand->iRow != iRow) continue; 2449 j = lpBand->rcBand.bottom - lpBand->rcBand.top; 2450 if (j > ret) ret = j; 2451 } 2452 2453 TRACE("row %d, height %d\n", iRow, ret); 2454 2455 return ret; 2456 } 2457 2458 2459 static inline LRESULT 2460 REBAR_GetTextColor (const REBAR_INFO *infoPtr) 2461 { 2462 TRACE("text color 0x%06x!\n", infoPtr->clrText); 2463 2464 return infoPtr->clrText; 2465 } 2466 2467 2468 static inline LRESULT 2469 REBAR_GetToolTips (const REBAR_INFO *infoPtr) 2470 { 2471 return (LRESULT)infoPtr->hwndToolTip; 2472 } 2473 2474 2475 static inline LRESULT 2476 REBAR_GetUnicodeFormat (const REBAR_INFO *infoPtr) 2477 { 2478 TRACE("%s hwnd=%p\n", 2479 infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); 2480 2481 return infoPtr->bUnicode; 2482 } 2483 2484 2485 static inline LRESULT 2486 REBAR_GetVersion (const REBAR_INFO *infoPtr) 2487 { 2488 TRACE("version %d\n", infoPtr->iVersion); 2489 return infoPtr->iVersion; 2490 } 2491 2492 2493 static LRESULT 2494 REBAR_HitTest (const REBAR_INFO *infoPtr, LPRBHITTESTINFO lprbht) 2495 { 2496 if (!lprbht) 2497 return -1; 2498 2499 REBAR_InternalHitTest (infoPtr, &lprbht->pt, &lprbht->flags, &lprbht->iBand); 2500 2501 return lprbht->iBand; 2502 } 2503 2504 2505 static LRESULT 2506 REBAR_IdToIndex (const REBAR_INFO *infoPtr, UINT uId) 2507 { 2508 UINT i; 2509 2510 if (infoPtr->uNumBands < 1) 2511 return -1; 2512 2513 for (i = 0; i < infoPtr->uNumBands; i++) { 2514 if (REBAR_GetBand(infoPtr, i)->wID == uId) { 2515 TRACE("id %u is band %u found!\n", uId, i); 2516 return i; 2517 } 2518 } 2519 2520 TRACE("id %u is not found\n", uId); 2521 return -1; 2522 } 2523 2524 2525 static LRESULT 2526 REBAR_InsertBandT(REBAR_INFO *infoPtr, INT iIndex, const REBARBANDINFOW *lprbbi, BOOL bUnicode) 2527 { 2528 REBAR_BAND *lpBand; 2529 2530 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 2531 return FALSE; 2532 2533 /* trace the index as signed to see the -1 */ 2534 TRACE("insert band at %d (bUnicode=%d)!\n", iIndex, bUnicode); 2535 REBAR_DumpBandInfo(lprbbi); 2536 2537 if (!(lpBand = Alloc(sizeof(REBAR_BAND)))) return FALSE; 2538 if ((iIndex == -1) || (iIndex > infoPtr->uNumBands)) 2539 iIndex = infoPtr->uNumBands; 2540 if (DPA_InsertPtr(infoPtr->bands, iIndex, lpBand) == -1) 2541 { 2542 Free(lpBand); 2543 return FALSE; 2544 } 2545 infoPtr->uNumBands++; 2546 2547 TRACE("index %d!\n", iIndex); 2548 2549 /* initialize band */ 2550 memset(lpBand, 0, sizeof(*lpBand)); 2551 #ifdef __REACTOS__ 2552 lpBand->clrFore = infoPtr->clrText == CLR_NONE ? CLR_DEFAULT : infoPtr->clrText; 2553 lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? CLR_DEFAULT : infoPtr->clrBk; 2554 #else 2555 lpBand->clrFore = infoPtr->clrText == CLR_NONE ? infoPtr->clrBtnText : 2556 infoPtr->clrText; 2557 lpBand->clrBack = infoPtr->clrBk == CLR_NONE ? infoPtr->clrBtnFace : 2558 infoPtr->clrBk; 2559 #endif 2560 lpBand->iImage = -1; 2561 2562 REBAR_CommonSetupBand(infoPtr->hwndSelf, lprbbi, lpBand); 2563 2564 /* Make sure the defaults for these are correct */ 2565 if (lprbbi->cbSize < REBARBANDINFOA_V6_SIZE || !(lpBand->fStyle & RBBS_VARIABLEHEIGHT)) { 2566 lpBand->cyChild = lpBand->cyMinChild; 2567 lpBand->cyMaxChild = 0x7fffffff; 2568 lpBand->cyIntegral = 0; 2569 } 2570 2571 if ((lprbbi->fMask & RBBIM_TEXT) && (lprbbi->lpText)) { 2572 if (bUnicode) 2573 Str_SetPtrW(&lpBand->lpText, lprbbi->lpText); 2574 else 2575 Str_SetPtrAtoW(&lpBand->lpText, (LPSTR)lprbbi->lpText); 2576 } 2577 2578 REBAR_ValidateBand (infoPtr, lpBand); 2579 /* On insert of second band, revalidate band 1 to possible add gripper */ 2580 if (infoPtr->uNumBands == 2) 2581 REBAR_ValidateBand (infoPtr, REBAR_GetBand(infoPtr, 0)); 2582 2583 REBAR_DumpBand (infoPtr); 2584 2585 REBAR_Layout(infoPtr); 2586 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 2587 2588 return TRUE; 2589 } 2590 2591 2592 static LRESULT 2593 REBAR_MaximizeBand (const REBAR_INFO *infoPtr, INT iBand, LPARAM lParam) 2594 { 2595 REBAR_BAND *lpBand; 2596 int iRowBegin, iRowEnd; 2597 int cxDesired, extra, extraOrig; 2598 int cxIdealBand; 2599 2600 /* Validate */ 2601 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) { 2602 /* error !!! */ 2603 ERR("Illegal MaximizeBand, requested=%d, current band count=%d\n", 2604 iBand, infoPtr->uNumBands); 2605 return FALSE; 2606 } 2607 2608 lpBand = REBAR_GetBand(infoPtr, iBand); 2609 2610 if (lpBand->fStyle & RBBS_HIDDEN) 2611 { 2612 /* Windows is buggy and creates a hole */ 2613 WARN("Ignoring maximize request on a hidden band (%d)\n", iBand); 2614 return FALSE; 2615 } 2616 2617 cxIdealBand = lpBand->cxIdeal + lpBand->cxHeader + REBAR_POST_CHILD; 2618 if (lParam && (lpBand->cxEffective < cxIdealBand)) 2619 cxDesired = cxIdealBand; 2620 else 2621 cxDesired = infoPtr->calcSize.cx; 2622 2623 iRowBegin = get_row_begin_for_band(infoPtr, iBand); 2624 iRowEnd = get_row_end_for_band(infoPtr, iBand); 2625 extraOrig = extra = cxDesired - lpBand->cxEffective; 2626 if (extra > 0) 2627 extra = REBAR_ShrinkBandsRTL(infoPtr, iRowBegin, iBand, extra, TRUE); 2628 if (extra > 0) 2629 extra = REBAR_ShrinkBandsLTR(infoPtr, next_visible(infoPtr, iBand), iRowEnd, extra, TRUE); 2630 lpBand->cxEffective += extraOrig - extra; 2631 lpBand->cx = lpBand->cxEffective; 2632 TRACE("(%d, %ld): Wanted size %d, obtained %d (shrink %d, %d)\n", iBand, lParam, cxDesired, lpBand->cx, extraOrig, extra); 2633 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 2634 2635 if (infoPtr->dwStyle & CCS_VERT) 2636 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd); 2637 else 2638 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd); 2639 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 2640 return TRUE; 2641 2642 } 2643 2644 2645 static LRESULT 2646 REBAR_MinimizeBand (const REBAR_INFO *infoPtr, INT iBand) 2647 { 2648 REBAR_BAND *lpBand; 2649 int iPrev, iRowBegin, iRowEnd; 2650 2651 /* A "minimize" band is equivalent to "dragging" the gripper 2652 * of than band to the right till the band is only the size 2653 * of the cxHeader. 2654 */ 2655 2656 /* Validate */ 2657 if (infoPtr->uNumBands == 0 || iBand < 0 || iBand >= infoPtr->uNumBands) { 2658 /* error !!! */ 2659 ERR("Illegal MinimizeBand, requested=%d, current band count=%d\n", 2660 iBand, infoPtr->uNumBands); 2661 return FALSE; 2662 } 2663 2664 /* compute amount of movement and validate */ 2665 lpBand = REBAR_GetBand(infoPtr, iBand); 2666 2667 if (lpBand->fStyle & RBBS_HIDDEN) 2668 { 2669 /* Windows is buggy and creates a hole/overlap */ 2670 WARN("Ignoring minimize request on a hidden band (%d)\n", iBand); 2671 return FALSE; 2672 } 2673 2674 iPrev = prev_visible(infoPtr, iBand); 2675 /* if first band in row */ 2676 if (iPrev < 0 || REBAR_GetBand(infoPtr, iPrev)->iRow != lpBand->iRow) { 2677 int iNext = next_visible(infoPtr, iBand); 2678 if (iNext < infoPtr->uNumBands && REBAR_GetBand(infoPtr, iNext)->iRow == lpBand->iRow) { 2679 TRACE("(%d): Minimizing the first band in row is by maximizing the second\n", iBand); 2680 REBAR_MaximizeBand(infoPtr, iNext, FALSE); 2681 } 2682 else 2683 TRACE("(%d): Only one band in row - nothing to do\n", iBand); 2684 return TRUE; 2685 } 2686 2687 REBAR_GetBand(infoPtr, iPrev)->cxEffective += lpBand->cxEffective - lpBand->cxMinBand; 2688 REBAR_GetBand(infoPtr, iPrev)->cx = REBAR_GetBand(infoPtr, iPrev)->cxEffective; 2689 lpBand->cx = lpBand->cxEffective = lpBand->cxMinBand; 2690 2691 iRowBegin = get_row_begin_for_band(infoPtr, iBand); 2692 iRowEnd = get_row_end_for_band(infoPtr, iBand); 2693 REBAR_SetRowRectsX(infoPtr, iRowBegin, iRowEnd); 2694 2695 if (infoPtr->dwStyle & CCS_VERT) 2696 REBAR_CalcVertBand(infoPtr, iRowBegin, iRowEnd); 2697 else 2698 REBAR_CalcHorzBand(infoPtr, iRowBegin, iRowEnd); 2699 REBAR_MoveChildWindows(infoPtr, iRowBegin, iRowEnd); 2700 return FALSE; 2701 } 2702 2703 2704 static LRESULT 2705 REBAR_MoveBand (REBAR_INFO *infoPtr, INT iFrom, INT iTo) 2706 { 2707 REBAR_BAND *lpBand; 2708 2709 /* Validate */ 2710 if ((infoPtr->uNumBands == 0) || 2711 (iFrom < 0) || iFrom >= infoPtr->uNumBands || 2712 (iTo < 0) || iTo >= infoPtr->uNumBands) { 2713 /* error !!! */ 2714 ERR("Illegal MoveBand, from=%d, to=%d, current band count=%d\n", 2715 iFrom, iTo, infoPtr->uNumBands); 2716 return FALSE; 2717 } 2718 2719 lpBand = REBAR_GetBand(infoPtr, iFrom); 2720 DPA_DeletePtr(infoPtr->bands, iFrom); 2721 DPA_InsertPtr(infoPtr->bands, iTo, lpBand); 2722 2723 TRACE("moved band %d to index %d\n", iFrom, iTo); 2724 REBAR_DumpBand (infoPtr); 2725 2726 /* **************************************************** */ 2727 /* */ 2728 /* We do not do a REBAR_Layout here because the native */ 2729 /* control does not do that. The actual layout and */ 2730 /* repaint is done by the *next* real action, ex.: */ 2731 /* RB_INSERTBAND, RB_DELETEBAND, RB_SIZETORECT, etc. */ 2732 /* */ 2733 /* **************************************************** */ 2734 2735 return TRUE; 2736 } 2737 2738 2739 /* return TRUE if two strings are different */ 2740 static BOOL 2741 REBAR_strdifW( LPCWSTR a, LPCWSTR b ) 2742 { 2743 return ( (a && !b) || (b && !a) || (a && b && lstrcmpW(a, b) ) ); 2744 } 2745 2746 static LRESULT 2747 REBAR_SetBandInfoT(REBAR_INFO *infoPtr, INT iBand, const REBARBANDINFOW *lprbbi, BOOL bUnicode) 2748 { 2749 REBAR_BAND *lpBand; 2750 UINT uChanged; 2751 2752 if (!lprbbi || lprbbi->cbSize < REBARBANDINFOA_V3_SIZE) 2753 return FALSE; 2754 2755 if (iBand >= infoPtr->uNumBands) 2756 return FALSE; 2757 2758 TRACE("index %d\n", iBand); 2759 REBAR_DumpBandInfo (lprbbi); 2760 2761 /* set band information */ 2762 lpBand = REBAR_GetBand(infoPtr, iBand); 2763 2764 uChanged = REBAR_CommonSetupBand (infoPtr->hwndSelf, lprbbi, lpBand); 2765 if (lprbbi->fMask & RBBIM_TEXT) { 2766 LPWSTR wstr = NULL; 2767 if (bUnicode) 2768 Str_SetPtrW(&wstr, lprbbi->lpText); 2769 else 2770 Str_SetPtrAtoW(&wstr, (LPSTR)lprbbi->lpText); 2771 2772 if (REBAR_strdifW(wstr, lpBand->lpText)) { 2773 Free(lpBand->lpText); 2774 lpBand->lpText = wstr; 2775 uChanged |= RBBIM_TEXT; 2776 } 2777 else 2778 Free(wstr); 2779 } 2780 2781 REBAR_ValidateBand (infoPtr, lpBand); 2782 2783 REBAR_DumpBand (infoPtr); 2784 2785 if (uChanged & (RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE | RBBIM_IMAGE)) { 2786 REBAR_Layout(infoPtr); 2787 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 2788 } 2789 2790 return TRUE; 2791 } 2792 2793 2794 static LRESULT 2795 REBAR_SetBarInfo (REBAR_INFO *infoPtr, const REBARINFO *lpInfo) 2796 { 2797 REBAR_BAND *lpBand; 2798 UINT i; 2799 2800 if (!lpInfo || lpInfo->cbSize < sizeof (REBARINFO)) 2801 return FALSE; 2802 2803 TRACE("setting bar info!\n"); 2804 2805 if (lpInfo->fMask & RBIM_IMAGELIST) { 2806 infoPtr->himl = lpInfo->himl; 2807 if (infoPtr->himl) { 2808 INT cx, cy; 2809 ImageList_GetIconSize (infoPtr->himl, &cx, &cy); 2810 infoPtr->imageSize.cx = cx; 2811 infoPtr->imageSize.cy = cy; 2812 } 2813 else { 2814 infoPtr->imageSize.cx = 0; 2815 infoPtr->imageSize.cy = 0; 2816 } 2817 TRACE("new image cx=%d, cy=%d\n", infoPtr->imageSize.cx, 2818 infoPtr->imageSize.cy); 2819 } 2820 2821 /* revalidate all bands to reset flags for images in headers of bands */ 2822 for (i=0; i<infoPtr->uNumBands; i++) { 2823 lpBand = REBAR_GetBand(infoPtr, i); 2824 REBAR_ValidateBand (infoPtr, lpBand); 2825 } 2826 2827 return TRUE; 2828 } 2829 2830 2831 static LRESULT 2832 REBAR_SetBkColor (REBAR_INFO *infoPtr, COLORREF clr) 2833 { 2834 COLORREF clrTemp; 2835 2836 clrTemp = infoPtr->clrBk; 2837 infoPtr->clrBk = clr; 2838 2839 TRACE("background color 0x%06x!\n", infoPtr->clrBk); 2840 2841 return clrTemp; 2842 } 2843 2844 2845 /* << REBAR_SetColorScheme >> */ 2846 /* << REBAR_SetPalette >> */ 2847 2848 2849 static LRESULT 2850 REBAR_SetParent (REBAR_INFO *infoPtr, HWND parent) 2851 { 2852 HWND hwndTemp = infoPtr->hwndNotify; 2853 2854 infoPtr->hwndNotify = parent; 2855 2856 return (LRESULT)hwndTemp; 2857 } 2858 2859 2860 static LRESULT 2861 REBAR_SetTextColor (REBAR_INFO *infoPtr, COLORREF clr) 2862 { 2863 COLORREF clrTemp; 2864 2865 clrTemp = infoPtr->clrText; 2866 infoPtr->clrText = clr; 2867 2868 TRACE("text color 0x%06x!\n", infoPtr->clrText); 2869 2870 return clrTemp; 2871 } 2872 2873 2874 /* << REBAR_SetTooltips >> */ 2875 2876 2877 static inline LRESULT 2878 REBAR_SetUnicodeFormat (REBAR_INFO *infoPtr, BOOL unicode) 2879 { 2880 BOOL bTemp = infoPtr->bUnicode; 2881 2882 TRACE("to %s hwnd=%p, was %s\n", 2883 unicode ? "TRUE" : "FALSE", infoPtr->hwndSelf, 2884 (bTemp) ? "TRUE" : "FALSE"); 2885 2886 infoPtr->bUnicode = unicode; 2887 2888 return bTemp; 2889 } 2890 2891 2892 static LRESULT 2893 REBAR_SetVersion (REBAR_INFO *infoPtr, INT iVersion) 2894 { 2895 INT iOldVersion = infoPtr->iVersion; 2896 2897 if (iVersion > COMCTL32_VERSION) 2898 return -1; 2899 2900 infoPtr->iVersion = iVersion; 2901 2902 TRACE("new version %d\n", iVersion); 2903 2904 return iOldVersion; 2905 } 2906 2907 2908 static LRESULT 2909 REBAR_ShowBand (REBAR_INFO *infoPtr, INT iBand, BOOL show) 2910 { 2911 REBAR_BAND *lpBand; 2912 2913 if (iBand < 0 || iBand >= infoPtr->uNumBands) 2914 return FALSE; 2915 2916 lpBand = REBAR_GetBand(infoPtr, iBand); 2917 2918 if (show) { 2919 TRACE("show band %d\n", iBand); 2920 lpBand->fStyle = lpBand->fStyle & ~RBBS_HIDDEN; 2921 if (IsWindow (lpBand->hwndChild)) 2922 ShowWindow (lpBand->hwndChild, SW_SHOW); 2923 } 2924 else { 2925 TRACE("hide band %d\n", iBand); 2926 lpBand->fStyle = lpBand->fStyle | RBBS_HIDDEN; 2927 if (IsWindow (lpBand->hwndChild)) 2928 ShowWindow (lpBand->hwndChild, SW_HIDE); 2929 } 2930 2931 REBAR_Layout(infoPtr); 2932 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 2933 2934 return TRUE; 2935 } 2936 2937 2938 static LRESULT 2939 #ifdef __REACTOS__ 2940 REBAR_SizeToRect (REBAR_INFO *infoPtr, WPARAM flags, RECT *lpRect) 2941 #else 2942 REBAR_SizeToRect (REBAR_INFO *infoPtr, const RECT *lpRect) 2943 #endif 2944 { 2945 if (!lpRect) return FALSE; 2946 2947 TRACE("[%s]\n", wine_dbgstr_rect(lpRect)); 2948 REBAR_SizeToHeight(infoPtr, get_rect_cy(infoPtr, lpRect)); 2949 2950 #ifdef __REACTOS__ 2951 /* Note that this undocumented flag is available on comctl32 v6 or later */ 2952 if ((flags & RBSTR_CHANGERECT) != 0) 2953 { 2954 RECT rcRebar; 2955 GetClientRect(infoPtr->hwndSelf, &rcRebar); 2956 lpRect->bottom = lpRect->top + (rcRebar.bottom - rcRebar.top); 2957 } 2958 #endif 2959 return TRUE; 2960 } 2961 2962 2963 2964 static LRESULT 2965 REBAR_Create (REBAR_INFO *infoPtr, LPCREATESTRUCTW cs) 2966 { 2967 RECT wnrc1, clrc1; 2968 2969 if (TRACE_ON(rebar)) { 2970 GetWindowRect(infoPtr->hwndSelf, &wnrc1); 2971 GetClientRect(infoPtr->hwndSelf, &clrc1); 2972 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n", 2973 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1), 2974 cs->x, cs->y, cs->cx, cs->cy); 2975 } 2976 2977 TRACE("created!\n"); 2978 2979 if (OpenThemeData (infoPtr->hwndSelf, themeClass)) 2980 { 2981 /* native seems to clear WS_BORDER when themed */ 2982 infoPtr->dwStyle &= ~WS_BORDER; 2983 } 2984 2985 return 0; 2986 } 2987 2988 2989 static LRESULT 2990 REBAR_Destroy (REBAR_INFO *infoPtr) 2991 { 2992 REBAR_BAND *lpBand; 2993 UINT i; 2994 2995 /* clean up each band */ 2996 for (i = 0; i < infoPtr->uNumBands; i++) { 2997 lpBand = REBAR_GetBand(infoPtr, i); 2998 2999 /* delete text strings */ 3000 Free (lpBand->lpText); 3001 lpBand->lpText = NULL; 3002 /* destroy child window */ 3003 DestroyWindow (lpBand->hwndChild); 3004 Free (lpBand); 3005 } 3006 3007 /* free band array */ 3008 DPA_Destroy (infoPtr->bands); 3009 infoPtr->bands = NULL; 3010 3011 DestroyCursor (infoPtr->hcurArrow); 3012 DestroyCursor (infoPtr->hcurHorz); 3013 DestroyCursor (infoPtr->hcurVert); 3014 DestroyCursor (infoPtr->hcurDrag); 3015 if (infoPtr->hDefaultFont) DeleteObject (infoPtr->hDefaultFont); 3016 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); 3017 3018 CloseThemeData (GetWindowTheme (infoPtr->hwndSelf)); 3019 3020 /* free rebar info data */ 3021 Free (infoPtr); 3022 TRACE("destroyed!\n"); 3023 return 0; 3024 } 3025 3026 static LRESULT 3027 REBAR_GetFont (const REBAR_INFO *infoPtr) 3028 { 3029 return (LRESULT)infoPtr->hFont; 3030 } 3031 3032 static LRESULT 3033 REBAR_PushChevron(const REBAR_INFO *infoPtr, UINT uBand, LPARAM lParam) 3034 { 3035 if (uBand < infoPtr->uNumBands) 3036 { 3037 NMREBARCHEVRON nmrbc; 3038 REBAR_BAND *lpBand = REBAR_GetBand(infoPtr, uBand); 3039 3040 TRACE("Pressed chevron on band %u\n", uBand); 3041 3042 /* redraw chevron in pushed state */ 3043 lpBand->fDraw |= DRAW_CHEVRONPUSHED; 3044 RedrawWindow(infoPtr->hwndSelf, &lpBand->rcChevron,0, 3045 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); 3046 3047 /* notify app so it can display a popup menu or whatever */ 3048 nmrbc.uBand = uBand; 3049 nmrbc.wID = lpBand->wID; 3050 nmrbc.lParam = lpBand->lParam; 3051 nmrbc.rc = lpBand->rcChevron; 3052 nmrbc.lParamNM = lParam; 3053 REBAR_Notify((NMHDR*)&nmrbc, infoPtr, RBN_CHEVRONPUSHED); 3054 3055 /* redraw chevron in previous state */ 3056 lpBand->fDraw &= ~DRAW_CHEVRONPUSHED; 3057 InvalidateRect(infoPtr->hwndSelf, &lpBand->rcChevron, TRUE); 3058 3059 return TRUE; 3060 } 3061 return FALSE; 3062 } 3063 3064 static LRESULT 3065 REBAR_LButtonDown (REBAR_INFO *infoPtr, LPARAM lParam) 3066 { 3067 UINT htFlags; 3068 INT iHitBand; 3069 POINT ptMouseDown; 3070 ptMouseDown.x = (short)LOWORD(lParam); 3071 ptMouseDown.y = (short)HIWORD(lParam); 3072 3073 REBAR_InternalHitTest(infoPtr, &ptMouseDown, &htFlags, &iHitBand); 3074 3075 if (htFlags == RBHT_CHEVRON) 3076 { 3077 REBAR_PushChevron(infoPtr, iHitBand, 0); 3078 } 3079 else if (htFlags == RBHT_GRABBER || htFlags == RBHT_CAPTION) 3080 { 3081 REBAR_BAND *lpBand; 3082 3083 TRACE("Starting drag\n"); 3084 3085 lpBand = REBAR_GetBand(infoPtr, iHitBand); 3086 3087 SetCapture (infoPtr->hwndSelf); 3088 infoPtr->iGrabbedBand = iHitBand; 3089 3090 /* save off the LOWORD and HIWORD of lParam as initial x,y */ 3091 infoPtr->dragStart.x = (short)LOWORD(lParam); 3092 infoPtr->dragStart.y = (short)HIWORD(lParam); 3093 infoPtr->dragNow = infoPtr->dragStart; 3094 if (infoPtr->dwStyle & CCS_VERT) 3095 infoPtr->ihitoffset = infoPtr->dragStart.y - (lpBand->rcBand.left + REBAR_PRE_GRIPPER); 3096 else 3097 infoPtr->ihitoffset = infoPtr->dragStart.x - (lpBand->rcBand.left + REBAR_PRE_GRIPPER); 3098 } 3099 return 0; 3100 } 3101 3102 static LRESULT 3103 REBAR_LButtonUp (REBAR_INFO *infoPtr) 3104 { 3105 if (infoPtr->iGrabbedBand >= 0) 3106 { 3107 NMHDR layout; 3108 RECT rect; 3109 3110 infoPtr->dragStart.x = 0; 3111 infoPtr->dragStart.y = 0; 3112 infoPtr->dragNow = infoPtr->dragStart; 3113 3114 ReleaseCapture (); 3115 3116 if (infoPtr->fStatus & BEGIN_DRAG_ISSUED) { 3117 REBAR_Notify(&layout, infoPtr, RBN_LAYOUTCHANGED); 3118 REBAR_Notify_NMREBAR (infoPtr, infoPtr->iGrabbedBand, RBN_ENDDRAG); 3119 infoPtr->fStatus &= ~BEGIN_DRAG_ISSUED; 3120 } 3121 3122 infoPtr->iGrabbedBand = -1; 3123 3124 GetClientRect(infoPtr->hwndSelf, &rect); 3125 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 3126 } 3127 3128 return 0; 3129 } 3130 3131 static LRESULT 3132 REBAR_MouseLeave (REBAR_INFO *infoPtr) 3133 { 3134 if (infoPtr->ichevronhotBand >= 0) 3135 { 3136 REBAR_BAND *lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand); 3137 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) 3138 { 3139 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; 3140 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 3141 } 3142 } 3143 infoPtr->iOldBand = -1; 3144 infoPtr->ichevronhotBand = -2; 3145 3146 return TRUE; 3147 } 3148 3149 static LRESULT 3150 REBAR_MouseMove (REBAR_INFO *infoPtr, LPARAM lParam) 3151 { 3152 REBAR_BAND *lpChevronBand; 3153 POINT ptMove; 3154 3155 ptMove.x = (short)LOWORD(lParam); 3156 ptMove.y = (short)HIWORD(lParam); 3157 3158 /* if we are currently dragging a band */ 3159 if (infoPtr->iGrabbedBand >= 0) 3160 { 3161 REBAR_BAND *band; 3162 int yPtMove = (infoPtr->dwStyle & CCS_VERT ? ptMove.x : ptMove.y); 3163 3164 if (GetCapture() != infoPtr->hwndSelf) 3165 ERR("We are dragging but haven't got capture?!?\n"); 3166 3167 band = REBAR_GetBand(infoPtr, infoPtr->iGrabbedBand); 3168 3169 /* if mouse did not move much, exit */ 3170 if ((abs(ptMove.x - infoPtr->dragNow.x) <= mindragx) && 3171 (abs(ptMove.y - infoPtr->dragNow.y) <= mindragy)) return 0; 3172 3173 /* on first significant mouse movement, issue notify */ 3174 if (!(infoPtr->fStatus & BEGIN_DRAG_ISSUED)) { 3175 if (REBAR_Notify_NMREBAR (infoPtr, -1, RBN_BEGINDRAG)) { 3176 /* Notify returned TRUE - abort drag */ 3177 infoPtr->dragStart.x = 0; 3178 infoPtr->dragStart.y = 0; 3179 infoPtr->dragNow = infoPtr->dragStart; 3180 infoPtr->iGrabbedBand = -1; 3181 ReleaseCapture (); 3182 return 0; 3183 } 3184 infoPtr->fStatus |= BEGIN_DRAG_ISSUED; 3185 } 3186 3187 /* Test for valid drag case - must not be first band in row */ 3188 if ((yPtMove < band->rcBand.top) || 3189 (yPtMove > band->rcBand.bottom)) { 3190 REBAR_HandleUDDrag (infoPtr, &ptMove); 3191 } 3192 else { 3193 REBAR_HandleLRDrag (infoPtr, &ptMove); 3194 } 3195 } 3196 else 3197 { 3198 INT iHitBand; 3199 UINT htFlags; 3200 TRACKMOUSEEVENT trackinfo; 3201 3202 REBAR_InternalHitTest(infoPtr, &ptMove, &htFlags, &iHitBand); 3203 3204 if (infoPtr->iOldBand >= 0 && infoPtr->iOldBand == infoPtr->ichevronhotBand) 3205 { 3206 lpChevronBand = REBAR_GetBand(infoPtr, infoPtr->ichevronhotBand); 3207 if (lpChevronBand->fDraw & DRAW_CHEVRONHOT) 3208 { 3209 lpChevronBand->fDraw &= ~DRAW_CHEVRONHOT; 3210 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 3211 } 3212 infoPtr->ichevronhotBand = -2; 3213 } 3214 3215 if (htFlags == RBHT_CHEVRON) 3216 { 3217 /* fill in the TRACKMOUSEEVENT struct */ 3218 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); 3219 trackinfo.dwFlags = TME_QUERY; 3220 trackinfo.hwndTrack = infoPtr->hwndSelf; 3221 trackinfo.dwHoverTime = 0; 3222 3223 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ 3224 _TrackMouseEvent(&trackinfo); 3225 3226 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ 3227 if(!(trackinfo.dwFlags & TME_LEAVE)) 3228 { 3229 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ 3230 3231 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ 3232 /* and can properly deactivate the hot chevron */ 3233 _TrackMouseEvent(&trackinfo); 3234 } 3235 3236 lpChevronBand = REBAR_GetBand(infoPtr, iHitBand); 3237 if (!(lpChevronBand->fDraw & DRAW_CHEVRONHOT)) 3238 { 3239 lpChevronBand->fDraw |= DRAW_CHEVRONHOT; 3240 InvalidateRect(infoPtr->hwndSelf, &lpChevronBand->rcChevron, TRUE); 3241 infoPtr->ichevronhotBand = iHitBand; 3242 } 3243 } 3244 infoPtr->iOldBand = iHitBand; 3245 } 3246 3247 return 0; 3248 } 3249 3250 3251 static inline LRESULT 3252 REBAR_NCCalcSize (const REBAR_INFO *infoPtr, RECT *rect) 3253 { 3254 HTHEME theme; 3255 3256 if (infoPtr->dwStyle & WS_BORDER) { 3257 rect->left = min(rect->left + GetSystemMetrics(SM_CXEDGE), rect->right); 3258 rect->right = max(rect->right - GetSystemMetrics(SM_CXEDGE), rect->left); 3259 rect->top = min(rect->top + GetSystemMetrics(SM_CYEDGE), rect->bottom); 3260 rect->bottom = max(rect->bottom - GetSystemMetrics(SM_CYEDGE), rect->top); 3261 } 3262 else if ((theme = GetWindowTheme (infoPtr->hwndSelf))) 3263 { 3264 /* FIXME: should use GetThemeInt */ 3265 #ifdef __REACTOS__ 3266 rect->top = (rect->top + 1 < rect->bottom) ? rect->top : rect->bottom; 3267 #else 3268 rect->top = min(rect->top + 1, rect->bottom); 3269 #endif 3270 } 3271 TRACE("new client=(%s)\n", wine_dbgstr_rect(rect)); 3272 return 0; 3273 } 3274 3275 3276 static LRESULT 3277 REBAR_NCCreate (HWND hwnd, const CREATESTRUCTW *cs) 3278 { 3279 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); 3280 RECT wnrc1, clrc1; 3281 NONCLIENTMETRICSW ncm; 3282 HFONT tfont; 3283 3284 if (infoPtr) { 3285 ERR("Strange info structure pointer *not* NULL\n"); 3286 return FALSE; 3287 } 3288 3289 if (TRACE_ON(rebar)) { 3290 GetWindowRect(hwnd, &wnrc1); 3291 GetClientRect(hwnd, &clrc1); 3292 TRACE("window=(%s) client=(%s) cs=(%d,%d %dx%d)\n", 3293 wine_dbgstr_rect(&wnrc1), wine_dbgstr_rect(&clrc1), 3294 cs->x, cs->y, cs->cx, cs->cy); 3295 } 3296 3297 /* allocate memory for info structure */ 3298 infoPtr = Alloc (sizeof(REBAR_INFO)); 3299 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 3300 3301 /* initialize info structure - initial values are 0 */ 3302 infoPtr->clrBk = CLR_NONE; 3303 infoPtr->clrText = CLR_NONE; 3304 infoPtr->clrBtnText = comctl32_color.clrBtnText; 3305 infoPtr->clrBtnFace = comctl32_color.clrBtnFace; 3306 infoPtr->iOldBand = -1; 3307 infoPtr->ichevronhotBand = -2; 3308 infoPtr->iGrabbedBand = -1; 3309 infoPtr->hwndSelf = hwnd; 3310 infoPtr->DoRedraw = TRUE; 3311 infoPtr->hcurArrow = LoadCursorW (0, (LPWSTR)IDC_ARROW); 3312 infoPtr->hcurHorz = LoadCursorW (0, (LPWSTR)IDC_SIZEWE); 3313 infoPtr->hcurVert = LoadCursorW (0, (LPWSTR)IDC_SIZENS); 3314 infoPtr->hcurDrag = LoadCursorW (0, (LPWSTR)IDC_SIZE); 3315 infoPtr->fStatus = 0; 3316 infoPtr->hFont = GetStockObject (SYSTEM_FONT); 3317 infoPtr->bands = DPA_Create(8); 3318 3319 /* issue WM_NOTIFYFORMAT to get unicode status of parent */ 3320 REBAR_NotifyFormat(infoPtr, NF_REQUERY); 3321 3322 /* Stow away the original style */ 3323 infoPtr->orgStyle = cs->style; 3324 /* add necessary styles to the requested styles */ 3325 infoPtr->dwStyle = cs->style | WS_VISIBLE; 3326 if ((infoPtr->dwStyle & CCS_LAYOUT_MASK) == 0) 3327 infoPtr->dwStyle |= CCS_TOP; 3328 SetWindowLongW (hwnd, GWL_STYLE, infoPtr->dwStyle); 3329 3330 /* get font handle for Caption Font */ 3331 ncm.cbSize = sizeof(ncm); 3332 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0); 3333 /* if the font is bold, set to normal */ 3334 if (ncm.lfCaptionFont.lfWeight > FW_NORMAL) { 3335 ncm.lfCaptionFont.lfWeight = FW_NORMAL; 3336 } 3337 tfont = CreateFontIndirectW (&ncm.lfCaptionFont); 3338 if (tfont) { 3339 infoPtr->hFont = infoPtr->hDefaultFont = tfont; 3340 } 3341 3342 return TRUE; 3343 } 3344 3345 3346 static LRESULT 3347 REBAR_NCHitTest (const REBAR_INFO *infoPtr, LPARAM lParam) 3348 { 3349 NMMOUSE nmmouse; 3350 POINT clpt; 3351 INT i; 3352 UINT scrap; 3353 LRESULT ret = HTCLIENT; 3354 3355 /* 3356 * Differences from doc at MSDN (as observed with version 4.71 of 3357 * comctl32.dll 3358 * 1. doc says nmmouse.pt is in screen coord, trace shows client coord. 3359 * 2. if band is not identified .dwItemSpec is 0xffffffff. 3360 * 3. native always seems to return HTCLIENT if notify return is 0. 3361 */ 3362 3363 clpt.x = (short)LOWORD(lParam); 3364 clpt.y = (short)HIWORD(lParam); 3365 ScreenToClient (infoPtr->hwndSelf, &clpt); 3366 REBAR_InternalHitTest (infoPtr, &clpt, &scrap, 3367 (INT *)&nmmouse.dwItemSpec); 3368 nmmouse.dwItemData = 0; 3369 nmmouse.pt = clpt; 3370 #ifdef __REACTOS__ 3371 nmmouse.dwHitInfo = scrap; 3372 #else 3373 nmmouse.dwHitInfo = 0; 3374 #endif 3375 if ((i = REBAR_Notify((NMHDR *) &nmmouse, infoPtr, NM_NCHITTEST))) { 3376 TRACE("notify changed return value from %ld to %d\n", 3377 ret, i); 3378 ret = (LRESULT) i; 3379 } 3380 TRACE("returning %ld, client point %s\n", ret, wine_dbgstr_point(&clpt)); 3381 return ret; 3382 } 3383 3384 3385 static LRESULT 3386 REBAR_NCPaint (const REBAR_INFO *infoPtr) 3387 { 3388 RECT rcWindow; 3389 HDC hdc; 3390 HTHEME theme; 3391 3392 if (infoPtr->dwStyle & WS_MINIMIZE) 3393 return 0; /* Nothing to do */ 3394 3395 if (infoPtr->dwStyle & WS_BORDER) { 3396 3397 /* adjust rectangle and draw the necessary edge */ 3398 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) 3399 return 0; 3400 GetWindowRect (infoPtr->hwndSelf, &rcWindow); 3401 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 3402 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow)); 3403 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_RECT); 3404 ReleaseDC( infoPtr->hwndSelf, hdc ); 3405 } 3406 else if ((theme = GetWindowTheme (infoPtr->hwndSelf))) 3407 { 3408 /* adjust rectangle and draw the necessary edge */ 3409 if (!(hdc = GetDCEx( infoPtr->hwndSelf, 0, DCX_USESTYLE | DCX_WINDOW ))) 3410 return 0; 3411 GetWindowRect (infoPtr->hwndSelf, &rcWindow); 3412 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 3413 TRACE("rect (%s)\n", wine_dbgstr_rect(&rcWindow)); 3414 DrawThemeEdge (theme, hdc, 0, 0, &rcWindow, BDR_RAISEDINNER, BF_TOP, NULL); 3415 ReleaseDC( infoPtr->hwndSelf, hdc ); 3416 } 3417 3418 return 0; 3419 } 3420 3421 3422 static LRESULT 3423 REBAR_NotifyFormat (REBAR_INFO *infoPtr, LPARAM cmd) 3424 { 3425 INT i; 3426 3427 if (cmd == NF_REQUERY) { 3428 i = SendMessageW(REBAR_GetNotifyParent (infoPtr), 3429 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); 3430 if ((i != NFR_ANSI) && (i != NFR_UNICODE)) { 3431 ERR("wrong response to WM_NOTIFYFORMAT (%d), assuming ANSI\n", i); 3432 i = NFR_ANSI; 3433 } 3434 infoPtr->bUnicode = (i == NFR_UNICODE); 3435 return (LRESULT)i; 3436 } 3437 return (LRESULT)((infoPtr->bUnicode) ? NFR_UNICODE : NFR_ANSI); 3438 } 3439 3440 3441 static LRESULT 3442 REBAR_Paint (const REBAR_INFO *infoPtr, HDC hdc) 3443 { 3444 if (hdc) { 3445 TRACE("painting\n"); 3446 #ifdef __REACTOS__ 3447 REBAR_EraseBkGnd (infoPtr, hdc); 3448 #endif 3449 REBAR_Refresh (infoPtr, hdc); 3450 } else { 3451 PAINTSTRUCT ps; 3452 hdc = BeginPaint (infoPtr->hwndSelf, &ps); 3453 TRACE("painting (%s)\n", wine_dbgstr_rect(&ps.rcPaint)); 3454 if (ps.fErase) { 3455 /* Erase area of paint if requested */ 3456 REBAR_EraseBkGnd (infoPtr, hdc); 3457 } 3458 REBAR_Refresh (infoPtr, hdc); 3459 EndPaint (infoPtr->hwndSelf, &ps); 3460 } 3461 3462 return 0; 3463 } 3464 3465 3466 static LRESULT 3467 REBAR_SetCursor (const REBAR_INFO *infoPtr, LPARAM lParam) 3468 { 3469 POINT pt; 3470 UINT flags; 3471 3472 TRACE("code=0x%X id=0x%X\n", LOWORD(lParam), HIWORD(lParam)); 3473 3474 GetCursorPos (&pt); 3475 ScreenToClient (infoPtr->hwndSelf, &pt); 3476 3477 REBAR_InternalHitTest (infoPtr, &pt, &flags, NULL); 3478 3479 if (flags == RBHT_GRABBER) { 3480 if ((infoPtr->dwStyle & CCS_VERT) && 3481 !(infoPtr->dwStyle & RBS_VERTICALGRIPPER)) 3482 SetCursor (infoPtr->hcurVert); 3483 else 3484 SetCursor (infoPtr->hcurHorz); 3485 } 3486 else if (flags != RBHT_CLIENT) 3487 SetCursor (infoPtr->hcurArrow); 3488 3489 return 0; 3490 } 3491 3492 3493 static LRESULT 3494 REBAR_SetFont (REBAR_INFO *infoPtr, HFONT font) 3495 { 3496 REBAR_BAND *lpBand; 3497 UINT i; 3498 3499 infoPtr->hFont = font; 3500 3501 /* revalidate all bands to change sizes of text in headers of bands */ 3502 for (i=0; i<infoPtr->uNumBands; i++) { 3503 lpBand = REBAR_GetBand(infoPtr, i); 3504 REBAR_ValidateBand (infoPtr, lpBand); 3505 } 3506 3507 REBAR_Layout(infoPtr); 3508 return 0; 3509 } 3510 3511 3512 /***************************************************** 3513 * 3514 * Handles the WM_SETREDRAW message. 3515 * 3516 * Documentation: 3517 * According to testing V4.71 of COMCTL32 returns the 3518 * *previous* status of the redraw flag (either 0 or -1) 3519 * instead of the MSDN documented value of 0 if handled 3520 * 3521 *****************************************************/ 3522 static inline LRESULT 3523 REBAR_SetRedraw (REBAR_INFO *infoPtr, BOOL redraw) 3524 { 3525 BOOL oldredraw = infoPtr->DoRedraw; 3526 3527 TRACE("set to %s, fStatus=%08x\n", 3528 (redraw) ? "TRUE" : "FALSE", infoPtr->fStatus); 3529 infoPtr->DoRedraw = redraw; 3530 if (redraw) { 3531 if (infoPtr->fStatus & BAND_NEEDS_REDRAW) { 3532 REBAR_MoveChildWindows (infoPtr, 0, infoPtr->uNumBands); 3533 REBAR_ForceResize (infoPtr); 3534 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 3535 } 3536 infoPtr->fStatus &= ~BAND_NEEDS_REDRAW; 3537 } 3538 return (oldredraw) ? -1 : 0; 3539 } 3540 3541 3542 static LRESULT 3543 REBAR_Size (REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3544 { 3545 TRACE("wParam=%lx, lParam=%lx\n", wParam, lParam); 3546 3547 /* avoid _Layout resize recursion (but it shouldn't be infinite and it seems Windows does recurse) */ 3548 if (infoPtr->fStatus & SELF_RESIZE) { 3549 infoPtr->fStatus &= ~SELF_RESIZE; 3550 TRACE("SELF_RESIZE was set, reset, fStatus=%08x lparam=%08lx\n", 3551 infoPtr->fStatus, lParam); 3552 return 0; 3553 } 3554 3555 if (infoPtr->dwStyle & RBS_AUTOSIZE) 3556 REBAR_AutoSize(infoPtr, TRUE); 3557 else 3558 REBAR_Layout(infoPtr); 3559 3560 return 0; 3561 } 3562 3563 3564 static LRESULT 3565 REBAR_StyleChanged (REBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle) 3566 { 3567 TRACE("current style=%08x, styleOld=%08x, style being set to=%08x\n", 3568 infoPtr->dwStyle, lpStyle->styleOld, lpStyle->styleNew); 3569 if (nType == GWL_STYLE) 3570 { 3571 infoPtr->orgStyle = infoPtr->dwStyle = lpStyle->styleNew; 3572 if (GetWindowTheme (infoPtr->hwndSelf)) 3573 infoPtr->dwStyle &= ~WS_BORDER; 3574 /* maybe it should be COMMON_STYLES like in toolbar */ 3575 if ((lpStyle->styleNew ^ lpStyle->styleOld) & CCS_VERT) 3576 REBAR_Layout(infoPtr); 3577 } 3578 return FALSE; 3579 } 3580 3581 /* update theme after a WM_THEMECHANGED message */ 3582 static LRESULT theme_changed (REBAR_INFO* infoPtr) 3583 { 3584 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 3585 CloseThemeData (theme); 3586 theme = OpenThemeData (infoPtr->hwndSelf, themeClass); 3587 /* WS_BORDER disappears when theming is enabled and reappears when 3588 * disabled... */ 3589 infoPtr->dwStyle &= ~WS_BORDER; 3590 infoPtr->dwStyle |= theme ? 0 : (infoPtr->orgStyle & WS_BORDER); 3591 return 0; 3592 } 3593 3594 static LRESULT 3595 REBAR_WindowPosChanged (const REBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3596 { 3597 LRESULT ret; 3598 RECT rc; 3599 3600 ret = DefWindowProcW(infoPtr->hwndSelf, WM_WINDOWPOSCHANGED, 3601 wParam, lParam); 3602 GetWindowRect(infoPtr->hwndSelf, &rc); 3603 TRACE("hwnd %p new pos (%s)\n", infoPtr->hwndSelf, wine_dbgstr_rect(&rc)); 3604 return ret; 3605 } 3606 3607 3608 static LRESULT WINAPI 3609 REBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 3610 { 3611 REBAR_INFO *infoPtr = REBAR_GetInfoPtr (hwnd); 3612 3613 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", 3614 hwnd, uMsg, wParam, lParam); 3615 if (!infoPtr && (uMsg != WM_NCCREATE)) 3616 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 3617 switch (uMsg) 3618 { 3619 /* case RB_BEGINDRAG: */ 3620 3621 case RB_DELETEBAND: 3622 return REBAR_DeleteBand (infoPtr, wParam); 3623 3624 /* case RB_DRAGMOVE: */ 3625 /* case RB_ENDDRAG: */ 3626 3627 case RB_GETBANDBORDERS: 3628 return REBAR_GetBandBorders (infoPtr, wParam, (LPRECT)lParam); 3629 3630 case RB_GETBANDCOUNT: 3631 return REBAR_GetBandCount (infoPtr); 3632 3633 case RB_GETBANDINFO_OLD: 3634 case RB_GETBANDINFOA: 3635 case RB_GETBANDINFOW: 3636 return REBAR_GetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 3637 uMsg == RB_GETBANDINFOW); 3638 case RB_GETBARHEIGHT: 3639 return REBAR_GetBarHeight (infoPtr); 3640 3641 case RB_GETBARINFO: 3642 return REBAR_GetBarInfo (infoPtr, (LPREBARINFO)lParam); 3643 3644 case RB_GETBKCOLOR: 3645 return REBAR_GetBkColor (infoPtr); 3646 3647 /* case RB_GETCOLORSCHEME: */ 3648 /* case RB_GETDROPTARGET: */ 3649 3650 case RB_GETPALETTE: 3651 return REBAR_GetPalette (infoPtr); 3652 3653 case RB_GETRECT: 3654 return REBAR_GetRect (infoPtr, wParam, (LPRECT)lParam); 3655 3656 case RB_GETROWCOUNT: 3657 return REBAR_GetRowCount (infoPtr); 3658 3659 case RB_GETROWHEIGHT: 3660 return REBAR_GetRowHeight (infoPtr, wParam); 3661 3662 case RB_GETTEXTCOLOR: 3663 return REBAR_GetTextColor (infoPtr); 3664 3665 case RB_GETTOOLTIPS: 3666 return REBAR_GetToolTips (infoPtr); 3667 3668 case RB_GETUNICODEFORMAT: 3669 return REBAR_GetUnicodeFormat (infoPtr); 3670 3671 case CCM_GETVERSION: 3672 return REBAR_GetVersion (infoPtr); 3673 3674 case RB_HITTEST: 3675 return REBAR_HitTest (infoPtr, (LPRBHITTESTINFO)lParam); 3676 3677 case RB_IDTOINDEX: 3678 return REBAR_IdToIndex (infoPtr, wParam); 3679 3680 case RB_INSERTBANDA: 3681 case RB_INSERTBANDW: 3682 return REBAR_InsertBandT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 3683 uMsg == RB_INSERTBANDW); 3684 case RB_MAXIMIZEBAND: 3685 return REBAR_MaximizeBand (infoPtr, wParam, lParam); 3686 3687 case RB_MINIMIZEBAND: 3688 return REBAR_MinimizeBand (infoPtr, wParam); 3689 3690 case RB_MOVEBAND: 3691 return REBAR_MoveBand (infoPtr, wParam, lParam); 3692 3693 case RB_PUSHCHEVRON: 3694 return REBAR_PushChevron (infoPtr, wParam, lParam); 3695 3696 case RB_SETBANDINFOA: 3697 case RB_SETBANDINFOW: 3698 return REBAR_SetBandInfoT(infoPtr, wParam, (LPREBARBANDINFOW)lParam, 3699 uMsg == RB_SETBANDINFOW); 3700 case RB_SETBARINFO: 3701 return REBAR_SetBarInfo (infoPtr, (LPREBARINFO)lParam); 3702 3703 case RB_SETBKCOLOR: 3704 return REBAR_SetBkColor (infoPtr, lParam); 3705 3706 /* case RB_SETCOLORSCHEME: */ 3707 /* case RB_SETPALETTE: */ 3708 3709 case RB_SETPARENT: 3710 return REBAR_SetParent (infoPtr, (HWND)wParam); 3711 3712 case RB_SETTEXTCOLOR: 3713 return REBAR_SetTextColor (infoPtr, lParam); 3714 3715 /* case RB_SETTOOLTIPS: */ 3716 3717 case RB_SETUNICODEFORMAT: 3718 return REBAR_SetUnicodeFormat (infoPtr, wParam); 3719 3720 case CCM_SETVERSION: 3721 return REBAR_SetVersion (infoPtr, (INT)wParam); 3722 3723 case RB_SHOWBAND: 3724 return REBAR_ShowBand (infoPtr, wParam, lParam); 3725 3726 case RB_SIZETORECT: 3727 #ifdef __REACTOS__ 3728 return REBAR_SizeToRect (infoPtr, wParam, (LPRECT)lParam); 3729 #else 3730 return REBAR_SizeToRect (infoPtr, (LPCRECT)lParam); 3731 #endif 3732 3733 3734 /* Messages passed to parent */ 3735 case WM_COMMAND: 3736 case WM_DRAWITEM: 3737 case WM_NOTIFY: 3738 case WM_MEASUREITEM: 3739 return SendMessageW(REBAR_GetNotifyParent (infoPtr), uMsg, wParam, lParam); 3740 3741 3742 /* case WM_CHARTOITEM: supported according to ControlSpy */ 3743 3744 case WM_CREATE: 3745 return REBAR_Create (infoPtr, (LPCREATESTRUCTW)lParam); 3746 3747 case WM_DESTROY: 3748 return REBAR_Destroy (infoPtr); 3749 3750 case WM_ERASEBKGND: 3751 return REBAR_EraseBkGnd (infoPtr, (HDC)wParam); 3752 3753 case WM_GETFONT: 3754 return REBAR_GetFont (infoPtr); 3755 3756 /* case WM_LBUTTONDBLCLK: supported according to ControlSpy */ 3757 3758 case WM_LBUTTONDOWN: 3759 return REBAR_LButtonDown (infoPtr, lParam); 3760 3761 case WM_LBUTTONUP: 3762 return REBAR_LButtonUp (infoPtr); 3763 3764 case WM_MOUSEMOVE: 3765 return REBAR_MouseMove (infoPtr, lParam); 3766 3767 case WM_MOUSELEAVE: 3768 return REBAR_MouseLeave (infoPtr); 3769 3770 case WM_NCCALCSIZE: 3771 return REBAR_NCCalcSize (infoPtr, (RECT*)lParam); 3772 3773 case WM_NCCREATE: 3774 return REBAR_NCCreate (hwnd, (LPCREATESTRUCTW)lParam); 3775 3776 case WM_NCHITTEST: 3777 return REBAR_NCHitTest (infoPtr, lParam); 3778 3779 case WM_NCPAINT: 3780 return REBAR_NCPaint (infoPtr); 3781 3782 case WM_NOTIFYFORMAT: 3783 return REBAR_NotifyFormat (infoPtr, lParam); 3784 3785 case WM_PRINTCLIENT: 3786 case WM_PAINT: 3787 return REBAR_Paint (infoPtr, (HDC)wParam); 3788 3789 /* case WM_PALETTECHANGED: supported according to ControlSpy */ 3790 /* case WM_QUERYNEWPALETTE:supported according to ControlSpy */ 3791 /* case WM_RBUTTONDOWN: supported according to ControlSpy */ 3792 /* case WM_RBUTTONUP: supported according to ControlSpy */ 3793 3794 case WM_SETCURSOR: 3795 return REBAR_SetCursor (infoPtr, lParam); 3796 3797 case WM_SETFONT: 3798 return REBAR_SetFont (infoPtr, (HFONT)wParam); 3799 3800 case WM_SETREDRAW: 3801 return REBAR_SetRedraw (infoPtr, wParam); 3802 3803 case WM_SIZE: 3804 return REBAR_Size (infoPtr, wParam, lParam); 3805 3806 case WM_STYLECHANGED: 3807 return REBAR_StyleChanged (infoPtr, wParam, (LPSTYLESTRUCT)lParam); 3808 3809 case WM_THEMECHANGED: 3810 return theme_changed (infoPtr); 3811 3812 case WM_SYSCOLORCHANGE: 3813 COMCTL32_RefreshSysColors(); 3814 #ifdef __REACTOS__ 3815 /* r51522 - Properly support WM_SYSCOLORCHANGE */ 3816 infoPtr->clrBtnText = comctl32_color.clrBtnText; 3817 infoPtr->clrBtnFace = comctl32_color.clrBtnFace; 3818 #endif 3819 return 0; 3820 3821 /* case WM_VKEYTOITEM: supported according to ControlSpy */ 3822 /* case WM_WININICHANGE: */ 3823 3824 case WM_WINDOWPOSCHANGED: 3825 return REBAR_WindowPosChanged (infoPtr, wParam, lParam); 3826 3827 default: 3828 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 3829 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", 3830 uMsg, wParam, lParam); 3831 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 3832 } 3833 } 3834 3835 3836 VOID 3837 REBAR_Register (void) 3838 { 3839 WNDCLASSW wndClass; 3840 3841 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 3842 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; 3843 wndClass.lpfnWndProc = REBAR_WindowProc; 3844 wndClass.cbClsExtra = 0; 3845 wndClass.cbWndExtra = sizeof(REBAR_INFO *); 3846 wndClass.hCursor = 0; 3847 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 3848 #if GLATESTING 3849 wndClass.hbrBackground = CreateSolidBrush(RGB(0,128,0)); 3850 #endif 3851 wndClass.lpszClassName = REBARCLASSNAMEW; 3852 3853 RegisterClassW (&wndClass); 3854 3855 mindragx = GetSystemMetrics (SM_CXDRAG); 3856 mindragy = GetSystemMetrics (SM_CYDRAG); 3857 3858 } 3859 3860 3861 VOID 3862 REBAR_Unregister (void) 3863 { 3864 UnregisterClassW (REBARCLASSNAMEW, NULL); 3865 } 3866