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