1 /* 2 * Toolbar control 3 * 4 * Copyright 1998,1999 Eric Kohl 5 * Copyright 2000 Eric Kohl for CodeWeavers 6 * Copyright 2004 Robert Shearman 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 * 22 * NOTES 23 * 24 * This code was audited for completeness against the documented features 25 * of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman. 26 * 27 * Unless otherwise noted, we believe this code to be complete, as per 28 * the specification mentioned above. 29 * If you discover missing features or bugs please note them below. 30 * 31 * TODO: 32 * - Styles: 33 * - TBSTYLE_REGISTERDROP 34 * - TBSTYLE_EX_DOUBLEBUFFER 35 * - Messages: 36 * - TB_GETOBJECT 37 * - TB_INSERTMARKHITTEST 38 * - TB_SAVERESTORE 39 * - WM_WININICHANGE 40 * - Notifications: 41 * - NM_CHAR 42 * - TBN_GETOBJECT 43 * - TBN_SAVE 44 * - Button wrapping (under construction). 45 * - Fix TB_SETROWS and Separators. 46 * - iListGap custom draw support. 47 * 48 * Testing: 49 * - Run tests using Waite Group Windows95 API Bible Volume 2. 50 * The second cdrom contains executables addstr.exe, btncount.exe, 51 * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe, 52 * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe, 53 * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe, 54 * setparnt.exe, setrows.exe, toolwnd.exe. 55 * - Microsoft's controlspy examples. 56 * - Charles Petzold's 'Programming Windows': gadgets.exe 57 * 58 * Differences between MSDN and actual native control operation: 59 * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text 60 * to the right of the bitmap. Otherwise, this style is 61 * identical to TBSTYLE_FLAT." 62 * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL 63 * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result 64 * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does 65 * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001) 66 * 67 */ 68 69 #include "comctl32.h" 70 71 WINE_DEFAULT_DEBUG_CHANNEL(toolbar); 72 73 static HCURSOR hCursorDrag = NULL; 74 75 typedef struct 76 { 77 INT iBitmap; 78 INT idCommand; 79 BYTE fsState; 80 BYTE fsStyle; 81 BOOL bHot; 82 BOOL bDropDownPressed; 83 DWORD_PTR dwData; 84 INT_PTR iString; 85 INT nRow; 86 RECT rect; 87 INT cx; /* manually set size */ 88 } TBUTTON_INFO; 89 90 typedef struct 91 { 92 UINT nButtons; 93 HINSTANCE hInst; 94 UINT nID; 95 } TBITMAP_INFO; 96 97 typedef struct 98 { 99 HIMAGELIST himl; 100 INT id; 101 } IMLENTRY, *PIMLENTRY; 102 103 typedef struct 104 { 105 DWORD dwStructSize; /* size of TBBUTTON struct */ 106 INT nWidth; /* width of the toolbar */ 107 RECT client_rect; 108 RECT rcBound; /* bounding rectangle */ 109 INT nButtonHeight; 110 INT nButtonWidth; 111 INT nBitmapHeight; 112 INT nBitmapWidth; 113 INT nIndent; 114 INT nRows; /* number of button rows */ 115 INT nMaxTextRows; /* maximum number of text rows */ 116 INT cxMin; /* minimum button width */ 117 INT cxMax; /* maximum button width */ 118 INT nNumButtons; /* number of buttons */ 119 INT nNumBitmaps; /* number of bitmaps */ 120 INT nNumStrings; /* number of strings */ 121 INT nNumBitmapInfos; 122 INT nButtonDown; /* toolbar button being pressed or -1 if none */ 123 INT nButtonDrag; /* toolbar button being dragged or -1 if none */ 124 INT nOldHit; 125 INT nHotItem; /* index of the "hot" item */ 126 SIZE szPadding; /* padding values around button */ 127 SIZE szBarPadding; /* padding values around the toolbar (NOT USED BUT STORED) */ 128 SIZE szSpacing; /* spacing values between buttons */ 129 INT iTopMargin; /* the top margin */ 130 INT iListGap; /* default gap between text and image for toolbar with list style */ 131 HFONT hDefaultFont; 132 HFONT hFont; /* text font */ 133 HIMAGELIST himlInt; /* image list created internally */ 134 PIMLENTRY *himlDef; /* default image list array */ 135 INT cimlDef; /* default image list array count */ 136 PIMLENTRY *himlHot; /* hot image list array */ 137 INT cimlHot; /* hot image list array count */ 138 PIMLENTRY *himlDis; /* disabled image list array */ 139 INT cimlDis; /* disabled image list array count */ 140 HWND hwndToolTip; /* handle to tool tip control */ 141 HWND hwndNotify; /* handle to the window that gets notifications */ 142 HWND hwndSelf; /* my own handle */ 143 BOOL bAnchor; /* anchor highlight enabled */ 144 BOOL bDoRedraw; /* Redraw status */ 145 BOOL bDragOutSent; /* has TBN_DRAGOUT notification been sent for this drag? */ 146 BOOL bUnicode; /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */ 147 BOOL bCaptured; /* mouse captured? */ 148 DWORD dwStyle; /* regular toolbar style */ 149 DWORD dwExStyle; /* extended toolbar style */ 150 DWORD dwDTFlags; /* DrawText flags */ 151 152 COLORREF clrInsertMark; /* insert mark color */ 153 COLORREF clrBtnHighlight; /* color for Flat Separator */ 154 COLORREF clrBtnShadow; /* color for Flag Separator */ 155 INT iVersion; 156 LPWSTR pszTooltipText; /* temporary store for a string > 80 characters 157 * for TTN_GETDISPINFOW notification */ 158 TBINSERTMARK tbim; /* info on insertion mark */ 159 TBUTTON_INFO *buttons; /* pointer to button array */ 160 LPWSTR *strings; /* pointer to string array */ 161 TBITMAP_INFO *bitmaps; 162 } TOOLBAR_INFO, *PTOOLBAR_INFO; 163 164 165 /* used by customization dialog */ 166 typedef struct 167 { 168 PTOOLBAR_INFO tbInfo; 169 HWND tbHwnd; 170 } CUSTDLG_INFO, *PCUSTDLG_INFO; 171 172 typedef struct 173 { 174 TBBUTTON btn; 175 BOOL bVirtual; 176 BOOL bRemovable; 177 WCHAR text[64]; 178 } CUSTOMBUTTON, *PCUSTOMBUTTON; 179 180 typedef enum 181 { 182 IMAGE_LIST_DEFAULT, 183 IMAGE_LIST_HOT, 184 IMAGE_LIST_DISABLED 185 } IMAGE_LIST_TYPE; 186 187 #define SEPARATOR_WIDTH 8 188 #define TOP_BORDER 2 189 #define BOTTOM_BORDER 2 190 #define DDARROW_WIDTH 11 191 #define ARROW_HEIGHT 3 192 #define INSERTMARK_WIDTH 2 193 194 /* default padding inside a button */ 195 #define DEFPAD_CX 7 196 #define DEFPAD_CY 6 197 198 /* default space between buttons and between rows */ 199 #define DEFSPACE_CX 7 200 #define DEFSPACE_CY 6 201 202 #define DEFLISTGAP 4 203 204 /* vertical padding used in list mode when image is present */ 205 #define LISTPAD_CY 2 206 207 /* how wide to treat the bitmap if it isn't present */ 208 #define NONLIST_NOTEXT_OFFSET 2 209 210 #define TOOLBAR_NOWHERE (-1) 211 212 /* Used to find undocumented extended styles */ 213 #define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \ 214 TBSTYLE_EX_VERTICAL | \ 215 TBSTYLE_EX_MIXEDBUTTONS | \ 216 TBSTYLE_EX_DOUBLEBUFFER | \ 217 TBSTYLE_EX_HIDECLIPPEDBUTTONS) 218 219 /* all of the CCS_ styles */ 220 #define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \ 221 CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT) 222 223 #define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i) 224 #define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0) 225 #define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id) 226 #define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id) 227 #define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id) 228 229 static const WCHAR themeClass[] = { 'T','o','o','l','b','a','r',0 }; 230 231 static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb); 232 static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, const CUSTOMBUTTON *btnInfo); 233 static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id); 234 static PIMLENTRY TOOLBAR_GetImageListEntry(const PIMLENTRY *pies, INT cies, INT id); 235 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies); 236 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id); 237 static LRESULT TOOLBAR_LButtonDown(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam); 238 static void TOOLBAR_LayoutToolbar(TOOLBAR_INFO *infoPtr); 239 static LRESULT TOOLBAR_AutoSize(TOOLBAR_INFO *infoPtr); 240 static void TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr); 241 static void TOOLBAR_TooltipAddTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button); 242 static void TOOLBAR_TooltipSetRect(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button); 243 244 245 static inline int default_top_margin(const TOOLBAR_INFO *infoPtr) 246 { 247 return (infoPtr->dwStyle & TBSTYLE_FLAT ? 0 : TOP_BORDER); 248 } 249 250 static inline BOOL TOOLBAR_HasDropDownArrows(DWORD exStyle) 251 { 252 return (exStyle & TBSTYLE_EX_DRAWDDARROWS) != 0; 253 } 254 255 static LPWSTR 256 TOOLBAR_GetText(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *btnPtr) 257 { 258 LPWSTR lpText = NULL; 259 260 /* NOTE: iString == -1 is undocumented */ 261 if (!IS_INTRESOURCE(btnPtr->iString) && (btnPtr->iString != -1)) 262 lpText = (LPWSTR)btnPtr->iString; 263 else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings)) 264 lpText = infoPtr->strings[btnPtr->iString]; 265 266 return lpText; 267 } 268 269 static void 270 TOOLBAR_DumpTBButton(const TBBUTTON *tbb, BOOL fUnicode) 271 { 272 TRACE("TBBUTTON: id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08lx (%s)\n", 273 tbb->idCommand,tbb->iBitmap, tbb->fsState, tbb->fsStyle, tbb->dwData, tbb->iString, 274 (fUnicode ? wine_dbgstr_w((LPWSTR)tbb->iString) : wine_dbgstr_a((LPSTR)tbb->iString))); 275 } 276 277 static void 278 TOOLBAR_DumpButton(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *bP, INT btn_num) 279 { 280 if (TRACE_ON(toolbar)){ 281 TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08lx\n", 282 btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap), 283 bP->fsState, bP->fsStyle, bP->dwData, bP->iString); 284 TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP))); 285 TRACE("button %d id %d, hot=%s, row=%d, rect=(%s)\n", 286 btn_num, bP->idCommand, (bP->bHot) ? "TRUE":"FALSE", bP->nRow, 287 wine_dbgstr_rect(&bP->rect)); 288 } 289 } 290 291 292 static void 293 TOOLBAR_DumpToolbar(const TOOLBAR_INFO *iP, INT line) 294 { 295 if (TRACE_ON(toolbar)) { 296 INT i; 297 298 TRACE("toolbar %p at line %d, exStyle=%08x, buttons=%d, bitmaps=%d, strings=%d, style=%08x\n", 299 iP->hwndSelf, line, 300 iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps, 301 iP->nNumStrings, iP->dwStyle); 302 TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n", 303 iP->hwndSelf, line, 304 iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis, 305 (iP->bDoRedraw) ? "TRUE" : "FALSE"); 306 for(i=0; i<iP->nNumButtons; i++) { 307 TOOLBAR_DumpButton(iP, &iP->buttons[i], i); 308 } 309 } 310 } 311 312 static inline BOOL 313 TOOLBAR_ButtonHasString(const TBUTTON_INFO *btnPtr) 314 { 315 return HIWORD(btnPtr->iString) && btnPtr->iString != -1; 316 } 317 318 /*********************************************************************** 319 * TOOLBAR_CheckStyle 320 * 321 * This function validates that the styles set are implemented and 322 * issues FIXMEs warning of possible problems. In a perfect world this 323 * function should be null. 324 */ 325 static void 326 TOOLBAR_CheckStyle (const TOOLBAR_INFO *infoPtr) 327 { 328 if (infoPtr->dwStyle & TBSTYLE_REGISTERDROP) 329 FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", infoPtr->hwndSelf); 330 } 331 332 333 static INT 334 TOOLBAR_SendNotify (NMHDR *nmhdr, const TOOLBAR_INFO *infoPtr, UINT code) 335 { 336 if(!IsWindow(infoPtr->hwndSelf)) 337 return 0; /* we have just been destroyed */ 338 339 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); 340 nmhdr->hwndFrom = infoPtr->hwndSelf; 341 nmhdr->code = code; 342 343 TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code, 344 (infoPtr->bUnicode) ? "via Unicode" : "via ANSI"); 345 346 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr); 347 } 348 349 /*********************************************************************** 350 * TOOLBAR_GetBitmapIndex 351 * 352 * This function returns the bitmap index associated with a button. 353 * If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO 354 * is issued to retrieve the index. 355 */ 356 static INT 357 TOOLBAR_GetBitmapIndex(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) 358 { 359 INT ret = btnPtr->iBitmap; 360 361 if (ret == I_IMAGECALLBACK) 362 { 363 /* issue TBN_GETDISPINFO */ 364 NMTBDISPINFOW nmgd; 365 366 memset(&nmgd, 0, sizeof(nmgd)); 367 nmgd.idCommand = btnPtr->idCommand; 368 nmgd.lParam = btnPtr->dwData; 369 nmgd.dwMask = TBNF_IMAGE; 370 nmgd.iImage = -1; 371 /* Windows also send TBN_GETDISPINFOW even if the control is ANSI */ 372 TOOLBAR_SendNotify(&nmgd.hdr, infoPtr, TBN_GETDISPINFOW); 373 if (nmgd.dwMask & TBNF_DI_SETITEM) 374 btnPtr->iBitmap = nmgd.iImage; 375 ret = nmgd.iImage; 376 TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08x, nNumBitmaps=%d\n", 377 ret, nmgd.dwMask, infoPtr->nNumBitmaps); 378 } 379 380 if (ret != I_IMAGENONE) 381 ret = GETIBITMAP(infoPtr, ret); 382 383 return ret; 384 } 385 386 387 static BOOL 388 TOOLBAR_IsValidBitmapIndex(const TOOLBAR_INFO *infoPtr, INT index) 389 { 390 HIMAGELIST himl; 391 INT id = GETHIMLID(infoPtr, index); 392 INT iBitmap = GETIBITMAP(infoPtr, index); 393 394 if (((himl = GETDEFIMAGELIST(infoPtr, id)) && 395 iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) || 396 (index == I_IMAGECALLBACK)) 397 return TRUE; 398 else 399 return FALSE; 400 } 401 402 403 static inline BOOL 404 TOOLBAR_IsValidImageList(const TOOLBAR_INFO *infoPtr, INT index) 405 { 406 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index)); 407 return (himl != NULL) && (ImageList_GetImageCount(himl) > 0); 408 } 409 410 411 /*********************************************************************** 412 * TOOLBAR_GetImageListForDrawing 413 * 414 * This function validates the bitmap index (including I_IMAGECALLBACK 415 * functionality) and returns the corresponding image list. 416 */ 417 static HIMAGELIST 418 TOOLBAR_GetImageListForDrawing (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, 419 IMAGE_LIST_TYPE imagelist, INT * index) 420 { 421 HIMAGELIST himl; 422 423 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) { 424 if (btnPtr->iBitmap == I_IMAGENONE) return NULL; 425 WARN("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n", 426 HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps); 427 return NULL; 428 } 429 430 if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) { 431 if ((*index == I_IMAGECALLBACK) || 432 (*index == I_IMAGENONE)) return NULL; 433 ERR("TBN_GETDISPINFO returned invalid index %d\n", 434 *index); 435 return NULL; 436 } 437 438 switch(imagelist) 439 { 440 case IMAGE_LIST_DEFAULT: 441 himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 442 break; 443 case IMAGE_LIST_HOT: 444 himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 445 break; 446 case IMAGE_LIST_DISABLED: 447 himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 448 break; 449 default: 450 himl = NULL; 451 FIXME("Shouldn't reach here\n"); 452 } 453 454 if (!himl) 455 TRACE("no image list\n"); 456 457 return himl; 458 } 459 460 461 static void 462 TOOLBAR_DrawFlatSeparator (const RECT *lpRect, HDC hdc, const TOOLBAR_INFO *infoPtr) 463 { 464 RECT myrect; 465 COLORREF oldcolor, newcolor; 466 467 myrect.left = (lpRect->left + lpRect->right) / 2 - 1; 468 myrect.right = myrect.left + 1; 469 myrect.top = lpRect->top + 2; 470 myrect.bottom = lpRect->bottom - 2; 471 472 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 473 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 474 oldcolor = SetBkColor (hdc, newcolor); 475 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 476 477 myrect.left = myrect.right; 478 myrect.right = myrect.left + 1; 479 480 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 481 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; 482 SetBkColor (hdc, newcolor); 483 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 484 485 SetBkColor (hdc, oldcolor); 486 } 487 488 489 /*********************************************************************** 490 * TOOLBAR_DrawFlatHorizontalSeparator 491 * 492 * This function draws horizontal separator for toolbars having CCS_VERT style. 493 * In this case, the separator is a pixel high line of COLOR_BTNSHADOW, 494 * followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators 495 * are horizontal as opposed to the vertical separators for not dropdown 496 * type. 497 * 498 * FIXME: It is possible that the height of each line is really SM_CYBORDER. 499 */ 500 static void 501 TOOLBAR_DrawFlatHorizontalSeparator (const RECT *lpRect, HDC hdc, 502 const TOOLBAR_INFO *infoPtr) 503 { 504 RECT myrect; 505 COLORREF oldcolor, newcolor; 506 507 myrect.left = lpRect->left; 508 myrect.right = lpRect->right; 509 myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2; 510 myrect.bottom = myrect.top + 1; 511 512 InflateRect (&myrect, -2, 0); 513 514 TRACE("rect=(%s)\n", wine_dbgstr_rect(&myrect)); 515 516 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 517 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 518 oldcolor = SetBkColor (hdc, newcolor); 519 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 520 521 myrect.top = myrect.bottom; 522 myrect.bottom = myrect.top + 1; 523 524 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 525 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; 526 SetBkColor (hdc, newcolor); 527 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 528 529 SetBkColor (hdc, oldcolor); 530 } 531 532 533 static void 534 TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr) 535 { 536 INT x, y; 537 HPEN hPen, hOldPen; 538 539 if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return; 540 hOldPen = SelectObject ( hdc, hPen ); 541 x = left + 2; 542 y = top; 543 MoveToEx (hdc, x, y, NULL); 544 LineTo (hdc, x+5, y++); x++; 545 MoveToEx (hdc, x, y, NULL); 546 LineTo (hdc, x+3, y++); x++; 547 MoveToEx (hdc, x, y, NULL); 548 LineTo (hdc, x+1, y); 549 SelectObject( hdc, hOldPen ); 550 DeleteObject( hPen ); 551 } 552 553 /* 554 * Draw the text string for this button. 555 * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef 556 * is non-zero, so we can simply check himlDef to see if we have 557 * an image list 558 */ 559 static void 560 TOOLBAR_DrawString (const TOOLBAR_INFO *infoPtr, RECT *rcText, LPCWSTR lpText, 561 const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) 562 { 563 HDC hdc = tbcd->nmcd.hdc; 564 HFONT hOldFont = 0; 565 COLORREF clrOld = 0; 566 COLORREF clrOldBk = 0; 567 int oldBkMode = 0; 568 UINT state = tbcd->nmcd.uItemState; 569 570 /* draw text */ 571 if (lpText && infoPtr->nMaxTextRows > 0) { 572 TRACE("string=%s rect=(%s)\n", debugstr_w(lpText), 573 wine_dbgstr_rect(rcText)); 574 575 hOldFont = SelectObject (hdc, infoPtr->hFont); 576 if ((state & CDIS_HOT) && (dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) { 577 clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); 578 } 579 else if (state & CDIS_DISABLED) { 580 clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight); 581 OffsetRect (rcText, 1, 1); 582 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); 583 SetTextColor (hdc, comctl32_color.clr3dShadow); 584 OffsetRect (rcText, -1, -1); 585 } 586 else if (state & CDIS_INDETERMINATE) { 587 clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow); 588 } 589 else if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK)) { 590 clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); 591 clrOldBk = SetBkColor (hdc, tbcd->clrMark); 592 oldBkMode = SetBkMode (hdc, tbcd->nHLStringBkMode); 593 } 594 else { 595 clrOld = SetTextColor (hdc, tbcd->clrText); 596 } 597 598 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); 599 SetTextColor (hdc, clrOld); 600 if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK)) 601 { 602 SetBkColor (hdc, clrOldBk); 603 SetBkMode (hdc, oldBkMode); 604 } 605 SelectObject (hdc, hOldFont); 606 } 607 } 608 609 610 static void 611 TOOLBAR_DrawPattern (const RECT *lpRect, const NMTBCUSTOMDRAW *tbcd) 612 { 613 HDC hdc = tbcd->nmcd.hdc; 614 HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither); 615 COLORREF clrTextOld; 616 COLORREF clrBkOld; 617 INT cx = lpRect->right - lpRect->left; 618 INT cy = lpRect->bottom - lpRect->top; 619 INT cxEdge = GetSystemMetrics(SM_CXEDGE); 620 INT cyEdge = GetSystemMetrics(SM_CYEDGE); 621 clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight); 622 clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace); 623 PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge, 624 cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY); 625 SetBkColor(hdc, clrBkOld); 626 SetTextColor(hdc, clrTextOld); 627 SelectObject (hdc, hbr); 628 } 629 630 631 static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags) 632 { 633 INT cx, cy; 634 HBITMAP hbmMask, hbmImage; 635 HDC hdcMask, hdcImage; 636 637 ImageList_GetIconSize(himl, &cx, &cy); 638 639 /* Create src image */ 640 hdcImage = CreateCompatibleDC(hdc); 641 hbmImage = CreateCompatibleBitmap(hdc, cx, cy); 642 SelectObject(hdcImage, hbmImage); 643 ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy, 644 RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags); 645 646 /* Create Mask */ 647 hdcMask = CreateCompatibleDC(0); 648 hbmMask = CreateBitmap(cx, cy, 1, 1, NULL); 649 SelectObject(hdcMask, hbmMask); 650 651 /* Remove the background and all white pixels */ 652 ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy, 653 RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK); 654 SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff)); 655 BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE); 656 657 /* draw the new mask 'etched' to hdc */ 658 SetBkColor(hdc, RGB(255, 255, 255)); 659 SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT)); 660 /* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */ 661 BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746); 662 SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW)); 663 BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746); 664 665 /* Cleanup */ 666 DeleteObject(hbmImage); 667 DeleteDC(hdcImage); 668 DeleteObject (hbmMask); 669 DeleteDC(hdcMask); 670 } 671 672 673 static UINT 674 TOOLBAR_TranslateState(const TBUTTON_INFO *btnPtr) 675 { 676 UINT retstate = 0; 677 678 retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0; 679 retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0; 680 retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED; 681 retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0; 682 retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0; 683 retstate |= ((btnPtr->fsState & (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) == (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) ? CDIS_INDETERMINATE : 0; 684 /* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */ 685 return retstate; 686 } 687 688 /* draws the image on a toolbar button */ 689 static void 690 TOOLBAR_DrawImage(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top, 691 const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) 692 { 693 HIMAGELIST himl = NULL; 694 BOOL draw_masked = FALSE; 695 INT index; 696 INT offset = 0; 697 UINT draw_flags = ILD_TRANSPARENT; 698 699 if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 700 { 701 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index); 702 if (!himl) 703 { 704 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 705 draw_masked = TRUE; 706 } 707 } 708 else if (tbcd->nmcd.uItemState & CDIS_CHECKED || 709 ((tbcd->nmcd.uItemState & CDIS_HOT) 710 && ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)))) 711 { 712 /* if hot, attempt to draw with hot image list, if fails, 713 use default image list */ 714 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index); 715 if (!himl) 716 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 717 } 718 else 719 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 720 721 if (!himl) 722 return; 723 724 if (!(dwItemCDFlag & TBCDRF_NOOFFSET) && 725 (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED))) 726 offset = 1; 727 728 if (!(dwItemCDFlag & TBCDRF_NOMARK) && 729 (tbcd->nmcd.uItemState & CDIS_MARKED)) 730 draw_flags |= ILD_BLEND50; 731 732 TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n", 733 index, himl, left, top, offset); 734 735 if (draw_masked) 736 TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); 737 else 738 ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); 739 } 740 741 /* draws a blank frame for a toolbar button */ 742 static void 743 TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, const RECT *rect, DWORD dwItemCDFlag) 744 { 745 HDC hdc = tbcd->nmcd.hdc; 746 RECT rc = *rect; 747 /* if the state is disabled or indeterminate then the button 748 * cannot have an interactive look like pressed or hot */ 749 BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) || 750 (tbcd->nmcd.uItemState & CDIS_INDETERMINATE); 751 BOOL pressed_look = !non_interactive_state && 752 ((tbcd->nmcd.uItemState & CDIS_SELECTED) || 753 (tbcd->nmcd.uItemState & CDIS_CHECKED)); 754 755 /* app don't want us to draw any edges */ 756 if (dwItemCDFlag & TBCDRF_NOEDGES) 757 return; 758 759 if (infoPtr->dwStyle & TBSTYLE_FLAT) 760 { 761 if (pressed_look) 762 DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT); 763 else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state) 764 DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT); 765 } 766 else 767 { 768 if (pressed_look) 769 DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); 770 else 771 DrawEdge (hdc, &rc, EDGE_RAISED, 772 BF_SOFT | BF_RECT | BF_MIDDLE); 773 } 774 } 775 776 static void 777 TOOLBAR_DrawSepDDArrow(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, RECT *rcArrow, BOOL bDropDownPressed, DWORD dwItemCDFlag) 778 { 779 HDC hdc = tbcd->nmcd.hdc; 780 int offset = 0; 781 BOOL pressed = bDropDownPressed || 782 (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)); 783 784 if (infoPtr->dwStyle & TBSTYLE_FLAT) 785 { 786 if (pressed) 787 DrawEdge (hdc, rcArrow, BDR_SUNKENOUTER, BF_RECT); 788 else if ( (tbcd->nmcd.uItemState & CDIS_HOT) && 789 !(tbcd->nmcd.uItemState & CDIS_DISABLED) && 790 !(tbcd->nmcd.uItemState & CDIS_INDETERMINATE)) 791 DrawEdge (hdc, rcArrow, BDR_RAISEDINNER, BF_RECT); 792 } 793 else 794 { 795 if (pressed) 796 DrawEdge (hdc, rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); 797 else 798 DrawEdge (hdc, rcArrow, EDGE_RAISED, 799 BF_SOFT | BF_RECT | BF_MIDDLE); 800 } 801 802 if (pressed) 803 offset = (dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; 804 805 if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 806 { 807 TOOLBAR_DrawArrow(hdc, rcArrow->left+1, rcArrow->top+1 + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); 808 TOOLBAR_DrawArrow(hdc, rcArrow->left, rcArrow->top + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); 809 } 810 else 811 TOOLBAR_DrawArrow(hdc, rcArrow->left + offset, rcArrow->top + offset + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 812 } 813 814 /* draws a complete toolbar button */ 815 static void 816 TOOLBAR_DrawButton (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HDC hdc, DWORD dwBaseCustDraw) 817 { 818 DWORD dwStyle = infoPtr->dwStyle; 819 BOOL hasDropDownArrow = (TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && 820 (btnPtr->fsStyle & BTNS_DROPDOWN)) || 821 (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); 822 BOOL drawSepDropDownArrow = hasDropDownArrow && 823 (~btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); 824 RECT rc, rcArrow, rcBitmap, rcText; 825 LPWSTR lpText = NULL; 826 NMTBCUSTOMDRAW tbcd; 827 DWORD ntfret; 828 INT offset; 829 INT oldBkMode; 830 DWORD dwItemCustDraw; 831 DWORD dwItemCDFlag; 832 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 833 834 rc = btnPtr->rect; 835 CopyRect (&rcArrow, &rc); 836 837 /* separator - doesn't send NM_CUSTOMDRAW */ 838 if (btnPtr->fsStyle & BTNS_SEP) { 839 if (theme) 840 { 841 DrawThemeBackground (theme, hdc, 842 (dwStyle & CCS_VERT) ? TP_SEPARATORVERT : TP_SEPARATOR, 0, 843 &rc, NULL); 844 } 845 else 846 /* with the FLAT style, iBitmap is the width and has already */ 847 /* been taken into consideration in calculating the width */ 848 /* so now we need to draw the vertical separator */ 849 /* empirical tests show that iBitmap can/will be non-zero */ 850 /* when drawing the vertical bar... */ 851 if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) { 852 if (dwStyle & CCS_VERT) { 853 RECT rcsep = rc; 854 InflateRect(&rcsep, -infoPtr->szPadding.cx, -infoPtr->szPadding.cy); 855 TOOLBAR_DrawFlatHorizontalSeparator (&rcsep, hdc, infoPtr); 856 } 857 else { 858 TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr); 859 } 860 } 861 else if (btnPtr->fsStyle != BTNS_SEP) { 862 FIXME("Draw some kind of separator: fsStyle=%x\n", 863 btnPtr->fsStyle); 864 } 865 return; 866 } 867 868 /* get a pointer to the text */ 869 lpText = TOOLBAR_GetText(infoPtr, btnPtr); 870 871 if (hasDropDownArrow) 872 { 873 int right; 874 875 if (dwStyle & TBSTYLE_FLAT) 876 right = max(rc.left, rc.right - DDARROW_WIDTH); 877 else 878 right = max(rc.left, rc.right - DDARROW_WIDTH - 2); 879 880 if (drawSepDropDownArrow) 881 rc.right = right; 882 883 rcArrow.left = right; 884 } 885 886 /* copy text & bitmap rects after adjusting for drop-down arrow 887 * so that text & bitmap is centered in the rectangle not containing 888 * the arrow */ 889 CopyRect(&rcText, &rc); 890 CopyRect(&rcBitmap, &rc); 891 892 /* Center the bitmap horizontally and vertically */ 893 if (dwStyle & TBSTYLE_LIST) 894 { 895 if (lpText && 896 infoPtr->nMaxTextRows > 0 && 897 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 898 (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) 899 rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2; 900 else 901 rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2; 902 } 903 else 904 rcBitmap.left += ((rc.right - rc.left) - infoPtr->nBitmapWidth) / 2; 905 906 rcBitmap.top += infoPtr->szPadding.cy / 2; 907 908 TRACE("iBitmap=%d, start=(%d,%d) w=%d, h=%d\n", 909 btnPtr->iBitmap, rcBitmap.left, rcBitmap.top, 910 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 911 TRACE("Text=%s\n", debugstr_w(lpText)); 912 TRACE("iListGap=%d, padding = { %d, %d }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy); 913 914 /* calculate text position */ 915 if (lpText) 916 { 917 rcText.left += GetSystemMetrics(SM_CXEDGE); 918 rcText.right -= GetSystemMetrics(SM_CXEDGE); 919 if (dwStyle & TBSTYLE_LIST) 920 { 921 rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2; 922 } 923 else 924 { 925 if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0) 926 rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1; 927 else 928 rcText.top += infoPtr->szPadding.cy/2 + 2; 929 } 930 } 931 932 /* Initialize fields in all cases, because we use these later 933 * NOTE: applications can and do alter these to customize their 934 * toolbars */ 935 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 936 tbcd.clrText = comctl32_color.clrBtnText; 937 tbcd.clrTextHighlight = comctl32_color.clrHighlightText; 938 tbcd.clrBtnFace = comctl32_color.clrBtnFace; 939 tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight; 940 tbcd.clrMark = comctl32_color.clrHighlight; 941 tbcd.clrHighlightHotTrack = 0; 942 tbcd.nStringBkMode = TRANSPARENT; 943 tbcd.nHLStringBkMode = OPAQUE; 944 tbcd.rcText.left = 0; 945 tbcd.rcText.top = 0; 946 tbcd.rcText.right = rcText.right - rc.left; 947 tbcd.rcText.bottom = rcText.bottom - rc.top; 948 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); 949 tbcd.nmcd.hdc = hdc; 950 tbcd.nmcd.rc = btnPtr->rect; 951 tbcd.hbrMonoDither = COMCTL32_hPattern55AABrush; 952 953 /* FIXME: what are these used for? */ 954 tbcd.hbrLines = 0; 955 tbcd.hpenLines = 0; 956 957 /* Issue Item Prepaint notify */ 958 dwItemCustDraw = 0; 959 dwItemCDFlag = 0; 960 if (dwBaseCustDraw & CDRF_NOTIFYITEMDRAW) 961 { 962 tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT; 963 tbcd.nmcd.dwItemSpec = btnPtr->idCommand; 964 tbcd.nmcd.lItemlParam = btnPtr->dwData; 965 ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 966 /* reset these fields so the user can't alter the behaviour like native */ 967 tbcd.nmcd.hdc = hdc; 968 tbcd.nmcd.rc = btnPtr->rect; 969 970 dwItemCustDraw = ntfret & 0xffff; 971 dwItemCDFlag = ntfret & 0xffff0000; 972 if (dwItemCustDraw & CDRF_SKIPDEFAULT) 973 return; 974 /* save the only part of the rect that the user can change */ 975 rcText.right = tbcd.rcText.right + rc.left; 976 rcText.bottom = tbcd.rcText.bottom + rc.top; 977 } 978 979 if (!(dwItemCDFlag & TBCDRF_NOOFFSET) && 980 (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))) 981 OffsetRect(&rcText, 1, 1); 982 983 if (!(tbcd.nmcd.uItemState & CDIS_HOT) && 984 ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE))) 985 TOOLBAR_DrawPattern (&rc, &tbcd); 986 987 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 988 && (tbcd.nmcd.uItemState & CDIS_HOT)) 989 { 990 if ( dwItemCDFlag & TBCDRF_HILITEHOTTRACK ) 991 { 992 COLORREF oldclr; 993 994 oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack); 995 ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0); 996 if (hasDropDownArrow) 997 ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0); 998 SetBkColor(hdc, oldclr); 999 } 1000 } 1001 1002 if (theme) 1003 { 1004 int partId = drawSepDropDownArrow ? TP_SPLITBUTTON : TP_BUTTON; 1005 int stateId = TS_NORMAL; 1006 1007 if (tbcd.nmcd.uItemState & CDIS_DISABLED) 1008 stateId = TS_DISABLED; 1009 else if (tbcd.nmcd.uItemState & CDIS_SELECTED) 1010 stateId = TS_PRESSED; 1011 else if (tbcd.nmcd.uItemState & CDIS_CHECKED) 1012 stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT; 1013 else if ((tbcd.nmcd.uItemState & CDIS_HOT) 1014 || (drawSepDropDownArrow && btnPtr->bDropDownPressed)) 1015 stateId = TS_HOT; 1016 1017 DrawThemeBackground (theme, hdc, partId, stateId, &rc, NULL); 1018 } 1019 else 1020 TOOLBAR_DrawFrame(infoPtr, &tbcd, &rc, dwItemCDFlag); 1021 1022 if (drawSepDropDownArrow) 1023 { 1024 if (theme) 1025 { 1026 int stateId = TS_NORMAL; 1027 1028 if (tbcd.nmcd.uItemState & CDIS_DISABLED) 1029 stateId = TS_DISABLED; 1030 else if (btnPtr->bDropDownPressed || (tbcd.nmcd.uItemState & CDIS_SELECTED)) 1031 stateId = TS_PRESSED; 1032 else if (tbcd.nmcd.uItemState & CDIS_CHECKED) 1033 stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT; 1034 else if (tbcd.nmcd.uItemState & CDIS_HOT) 1035 stateId = TS_HOT; 1036 1037 DrawThemeBackground (theme, hdc, TP_DROPDOWNBUTTON, stateId, &rcArrow, NULL); 1038 DrawThemeBackground (theme, hdc, TP_SPLITBUTTONDROPDOWN, stateId, &rcArrow, NULL); 1039 } 1040 else 1041 TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed, dwItemCDFlag); 1042 } 1043 1044 oldBkMode = SetBkMode (hdc, tbcd.nStringBkMode); 1045 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT)) 1046 TOOLBAR_DrawString (infoPtr, &rcText, lpText, &tbcd, dwItemCDFlag); 1047 SetBkMode (hdc, oldBkMode); 1048 1049 TOOLBAR_DrawImage(infoPtr, btnPtr, rcBitmap.left, rcBitmap.top, &tbcd, dwItemCDFlag); 1050 1051 if (hasDropDownArrow && !drawSepDropDownArrow) 1052 { 1053 if (tbcd.nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 1054 { 1055 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); 1056 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); 1057 } 1058 else if (tbcd.nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)) 1059 { 1060 offset = (dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; 1061 TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 1062 } 1063 else 1064 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 1065 } 1066 1067 if (dwItemCustDraw & CDRF_NOTIFYPOSTPAINT) 1068 { 1069 tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; 1070 TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 1071 } 1072 1073 } 1074 1075 1076 static void 1077 TOOLBAR_Refresh (TOOLBAR_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps) 1078 { 1079 TBUTTON_INFO *btnPtr; 1080 INT i; 1081 RECT rcTemp, rcClient; 1082 NMTBCUSTOMDRAW tbcd; 1083 DWORD ntfret; 1084 DWORD dwBaseCustDraw; 1085 1086 /* the app has told us not to redraw the toolbar */ 1087 if (!infoPtr->bDoRedraw) 1088 return; 1089 1090 /* if imagelist belongs to the app, it can be changed 1091 by the app after setting it */ 1092 if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt) 1093 { 1094 infoPtr->nNumBitmaps = 0; 1095 for (i = 0; i < infoPtr->cimlDef; i++) 1096 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); 1097 } 1098 1099 TOOLBAR_DumpToolbar (infoPtr, __LINE__); 1100 1101 /* change the imagelist icon size if we manage the list and it is necessary */ 1102 TOOLBAR_CheckImageListIconSize(infoPtr); 1103 1104 /* Send initial notify */ 1105 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 1106 tbcd.nmcd.dwDrawStage = CDDS_PREPAINT; 1107 tbcd.nmcd.hdc = hdc; 1108 tbcd.nmcd.rc = ps->rcPaint; 1109 ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 1110 dwBaseCustDraw = ntfret & 0xffff; 1111 1112 GetClientRect(infoPtr->hwndSelf, &rcClient); 1113 1114 /* redraw necessary buttons */ 1115 btnPtr = infoPtr->buttons; 1116 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) 1117 { 1118 BOOL bDraw; 1119 if (!RectVisible(hdc, &btnPtr->rect)) 1120 continue; 1121 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) 1122 { 1123 IntersectRect(&rcTemp, &rcClient, &btnPtr->rect); 1124 bDraw = EqualRect(&rcTemp, &btnPtr->rect); 1125 } 1126 else 1127 bDraw = TRUE; 1128 bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect)); 1129 bDraw = (btnPtr->fsState & TBSTATE_HIDDEN) ? FALSE : bDraw; 1130 if (bDraw) 1131 TOOLBAR_DrawButton(infoPtr, btnPtr, hdc, dwBaseCustDraw); 1132 } 1133 1134 /* draw insert mark if required */ 1135 if (infoPtr->tbim.iButton != -1) 1136 { 1137 RECT rcButton = infoPtr->buttons[infoPtr->tbim.iButton].rect; 1138 RECT rcInsertMark; 1139 rcInsertMark.top = rcButton.top; 1140 rcInsertMark.bottom = rcButton.bottom; 1141 if (infoPtr->tbim.dwFlags & TBIMHT_AFTER) 1142 rcInsertMark.left = rcInsertMark.right = rcButton.right; 1143 else 1144 rcInsertMark.left = rcInsertMark.right = rcButton.left - INSERTMARK_WIDTH; 1145 COMCTL32_DrawInsertMark(hdc, &rcInsertMark, infoPtr->clrInsertMark, FALSE); 1146 } 1147 1148 if (dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT) 1149 { 1150 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 1151 tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT; 1152 tbcd.nmcd.hdc = hdc; 1153 tbcd.nmcd.rc = ps->rcPaint; 1154 TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 1155 } 1156 } 1157 1158 /*********************************************************************** 1159 * TOOLBAR_MeasureString 1160 * 1161 * This function gets the width and height of a string in pixels. This 1162 * is done first by using GetTextExtentPoint to get the basic width 1163 * and height. The DrawText is called with DT_CALCRECT to get the exact 1164 * width. The reason is because the text may have more than one "&" (or 1165 * prefix characters as M$ likes to call them). The prefix character 1166 * indicates where the underline goes, except for the string "&&" which 1167 * is reduced to a single "&". GetTextExtentPoint does not process these 1168 * only DrawText does. Note that the BTNS_NOPREFIX is handled here. 1169 */ 1170 static void 1171 TOOLBAR_MeasureString(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *btnPtr, 1172 HDC hdc, LPSIZE lpSize) 1173 { 1174 RECT myrect; 1175 1176 lpSize->cx = 0; 1177 lpSize->cy = 0; 1178 1179 if (infoPtr->nMaxTextRows > 0 && 1180 !(btnPtr->fsState & TBSTATE_HIDDEN) && 1181 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 1182 (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) 1183 { 1184 LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr); 1185 1186 if(lpText != NULL) { 1187 /* first get size of all the text */ 1188 GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize); 1189 1190 /* feed above size into the rectangle for DrawText */ 1191 myrect.left = myrect.top = 0; 1192 myrect.right = lpSize->cx; 1193 myrect.bottom = lpSize->cy; 1194 1195 /* Use DrawText to get true size as drawn (less pesky "&") */ 1196 DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE | 1197 DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ? 1198 DT_NOPREFIX : 0)); 1199 1200 /* feed back to caller */ 1201 lpSize->cx = myrect.right; 1202 lpSize->cy = myrect.bottom; 1203 } 1204 } 1205 1206 TRACE("string size %d x %d!\n", lpSize->cx, lpSize->cy); 1207 } 1208 1209 /*********************************************************************** 1210 * TOOLBAR_CalcStrings 1211 * 1212 * This function walks through each string and measures it and returns 1213 * the largest height and width to caller. 1214 */ 1215 static void 1216 TOOLBAR_CalcStrings (const TOOLBAR_INFO *infoPtr, LPSIZE lpSize) 1217 { 1218 TBUTTON_INFO *btnPtr; 1219 INT i; 1220 SIZE sz; 1221 HDC hdc; 1222 HFONT hOldFont; 1223 1224 lpSize->cx = 0; 1225 lpSize->cy = 0; 1226 1227 if (infoPtr->nMaxTextRows == 0) 1228 return; 1229 1230 hdc = GetDC (infoPtr->hwndSelf); 1231 hOldFont = SelectObject (hdc, infoPtr->hFont); 1232 1233 if (infoPtr->nNumButtons == 0 && infoPtr->nNumStrings > 0) 1234 { 1235 TEXTMETRICW tm; 1236 1237 GetTextMetricsW(hdc, &tm); 1238 lpSize->cy = tm.tmHeight; 1239 } 1240 1241 btnPtr = infoPtr->buttons; 1242 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 1243 if(TOOLBAR_GetText(infoPtr, btnPtr)) 1244 { 1245 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); 1246 if (sz.cx > lpSize->cx) 1247 lpSize->cx = sz.cx; 1248 if (sz.cy > lpSize->cy) 1249 lpSize->cy = sz.cy; 1250 } 1251 } 1252 1253 SelectObject (hdc, hOldFont); 1254 ReleaseDC (infoPtr->hwndSelf, hdc); 1255 1256 TRACE("max string size %d x %d!\n", lpSize->cx, lpSize->cy); 1257 } 1258 1259 /*********************************************************************** 1260 * TOOLBAR_WrapToolbar 1261 * 1262 * This function walks through the buttons and separators in the 1263 * toolbar, and sets the TBSTATE_WRAP flag only on those items where 1264 * wrapping should occur based on the width of the toolbar window. 1265 * It does *not* calculate button placement itself. That task 1266 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage 1267 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE 1268 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items. 1269 * 1270 * Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_VERTICAL can be used also to allow 1271 * vertical toolbar lists. 1272 */ 1273 1274 static void 1275 TOOLBAR_WrapToolbar(TOOLBAR_INFO *infoPtr) 1276 { 1277 TBUTTON_INFO *btnPtr; 1278 INT x, cx, i, j; 1279 RECT rc; 1280 BOOL bButtonWrap; 1281 1282 /* When the toolbar window style is not TBSTYLE_WRAPABLE, */ 1283 /* no layout is necessary. Applications may use this style */ 1284 /* to perform their own layout on the toolbar. */ 1285 if (!(infoPtr->dwStyle & TBSTYLE_WRAPABLE) && 1286 !(infoPtr->dwExStyle & TBSTYLE_EX_VERTICAL)) return; 1287 1288 btnPtr = infoPtr->buttons; 1289 x = infoPtr->nIndent; 1290 1291 if (GetParent(infoPtr->hwndSelf)) 1292 { 1293 /* this can get the parents width, to know how far we can extend 1294 * this toolbar. We cannot use its height, as there may be multiple 1295 * toolbars in a rebar control 1296 */ 1297 GetClientRect(GetParent(infoPtr->hwndSelf), &rc); 1298 infoPtr->nWidth = rc.right - rc.left; 1299 } 1300 else 1301 { 1302 GetWindowRect(infoPtr->hwndSelf, &rc); 1303 infoPtr->nWidth = rc.right - rc.left; 1304 } 1305 1306 bButtonWrap = FALSE; 1307 1308 TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n", 1309 infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth, 1310 infoPtr->nIndent); 1311 1312 for (i = 0; i < infoPtr->nNumButtons; i++) 1313 { 1314 btnPtr[i].fsState &= ~TBSTATE_WRAP; 1315 1316 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 1317 continue; 1318 1319 if (btnPtr[i].cx > 0) 1320 cx = btnPtr[i].cx; 1321 /* horizontal separators are treated as buttons for width */ 1322 else if ((btnPtr[i].fsStyle & BTNS_SEP) && 1323 !(infoPtr->dwStyle & CCS_VERT)) 1324 cx = (btnPtr[i].iBitmap > 0) ? btnPtr[i].iBitmap : SEPARATOR_WIDTH; 1325 else 1326 cx = infoPtr->nButtonWidth; 1327 1328 /* Two or more adjacent separators form a separator group. */ 1329 /* The first separator in a group should be wrapped to the */ 1330 /* next row if the previous wrapping is on a button. */ 1331 if (bButtonWrap && 1332 (btnPtr[i].fsStyle & BTNS_SEP) && 1333 (i + 1 < infoPtr->nNumButtons) && 1334 (btnPtr[i + 1].fsStyle & BTNS_SEP)) 1335 { 1336 TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle); 1337 btnPtr[i].fsState |= TBSTATE_WRAP; 1338 x = infoPtr->nIndent; 1339 i++; 1340 bButtonWrap = FALSE; 1341 continue; 1342 } 1343 1344 /* The layout makes sure the bitmap is visible, but not the button. */ 1345 /* Test added to also wrap after a button that starts a row but */ 1346 /* is bigger than the area. - GA 8/01 */ 1347 if ((x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2 1348 > infoPtr->nWidth) || 1349 ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth))) 1350 { 1351 BOOL bFound = FALSE; 1352 1353 /* If the current button is a separator and not hidden, */ 1354 /* go to the next until it reaches a non separator. */ 1355 /* Wrap the last separator if it is before a button. */ 1356 while ((((btnPtr[i].fsStyle & BTNS_SEP) && 1357 !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) || 1358 (btnPtr[i].fsState & TBSTATE_HIDDEN)) && 1359 i < infoPtr->nNumButtons) 1360 { 1361 i++; 1362 bFound = TRUE; 1363 } 1364 1365 if (bFound && i < infoPtr->nNumButtons) 1366 { 1367 i--; 1368 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n", 1369 i, btnPtr[i].fsStyle, x, cx); 1370 btnPtr[i].fsState |= TBSTATE_WRAP; 1371 x = infoPtr->nIndent; 1372 bButtonWrap = FALSE; 1373 continue; 1374 } 1375 else if (i >= infoPtr->nNumButtons) 1376 break; 1377 1378 /* If the current button is not a separator, find the last */ 1379 /* separator and wrap it. */ 1380 for (j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) 1381 { 1382 if ((btnPtr[j].fsStyle & BTNS_SEP) && 1383 !(btnPtr[j].fsState & TBSTATE_HIDDEN)) 1384 { 1385 bFound = TRUE; 1386 i = j; 1387 TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n", 1388 i, btnPtr[i].fsStyle, x, cx); 1389 x = infoPtr->nIndent; 1390 btnPtr[j].fsState |= TBSTATE_WRAP; 1391 bButtonWrap = FALSE; 1392 break; 1393 } 1394 } 1395 1396 /* If no separator available for wrapping, wrap one of */ 1397 /* non-hidden previous button. */ 1398 if (!bFound) 1399 { 1400 for (j = i - 1; 1401 j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) 1402 { 1403 if (btnPtr[j].fsState & TBSTATE_HIDDEN) 1404 continue; 1405 1406 bFound = TRUE; 1407 i = j; 1408 TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n", 1409 i, btnPtr[i].fsStyle, x, cx); 1410 x = infoPtr->nIndent; 1411 btnPtr[j].fsState |= TBSTATE_WRAP; 1412 bButtonWrap = TRUE; 1413 break; 1414 } 1415 } 1416 1417 /* If all above failed, wrap the current button. */ 1418 if (!bFound) 1419 { 1420 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n", 1421 i, btnPtr[i].fsStyle, x, cx); 1422 btnPtr[i].fsState |= TBSTATE_WRAP; 1423 x = infoPtr->nIndent; 1424 if (btnPtr[i].fsStyle & BTNS_SEP) 1425 bButtonWrap = FALSE; 1426 else 1427 bButtonWrap = TRUE; 1428 } 1429 } 1430 else 1431 { 1432 TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n", 1433 i, btnPtr[i].fsStyle, x, cx); 1434 x += cx; 1435 } 1436 } 1437 } 1438 1439 1440 /*********************************************************************** 1441 * TOOLBAR_MeasureButton 1442 * 1443 * Calculates the width and height required for a button. Used in 1444 * TOOLBAR_CalcToolbar to set the all-button width and height and also for 1445 * the width of buttons that are autosized. 1446 * 1447 * Note that it would have been rather elegant to use one piece of code for 1448 * both the laying out of the toolbar and for controlling where button parts 1449 * are drawn, but the native control has inconsistencies between the two that 1450 * prevent this from being effectively. These inconsistencies can be seen as 1451 * artefacts where parts of the button appear outside of the bounding button 1452 * rectangle. 1453 * 1454 * There are several cases for the calculation of the button dimensions and 1455 * button part positioning: 1456 * 1457 * List 1458 * ==== 1459 * 1460 * With Bitmap: 1461 * 1462 * +--------------------------------------------------------+ ^ 1463 * | ^ ^ | | 1464 * | | pad.cy / 2 | centered | | 1465 * | pad.cx/2 + cxedge +--------------+ +------------+ | | DEFPAD_CY + 1466 * |<----------------->| nBitmapWidth | | Text | | | max(nBitmapHeight, szText.cy) 1467 * | |<------------>| | | | | 1468 * | +--------------+ +------------+ | | 1469 * |<-------------------------------------->| | | 1470 * | cxedge + iListGap + nBitmapWidth + 2 |<-----------> | | 1471 * | szText.cx | | 1472 * +--------------------------------------------------------+ - 1473 * <--------------------------------------------------------> 1474 * 2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx 1475 * 1476 * Without Bitmap (I_IMAGENONE): 1477 * 1478 * +-----------------------------------+ ^ 1479 * | ^ | | 1480 * | | centered | | LISTPAD_CY + 1481 * | +------------+ | | szText.cy 1482 * | | Text | | | 1483 * | | | | | 1484 * | +------------+ | | 1485 * |<----------------->| | | 1486 * | cxedge |<-----------> | | 1487 * | szText.cx | | 1488 * +-----------------------------------+ - 1489 * <-----------------------------------> 1490 * szText.cx + pad.cx 1491 * 1492 * Without text: 1493 * 1494 * +--------------------------------------+ ^ 1495 * | ^ | | 1496 * | | padding.cy/2 | | DEFPAD_CY + 1497 * | +------------+ | | nBitmapHeight 1498 * | | Bitmap | | | 1499 * | | | | | 1500 * | +------------+ | | 1501 * |<------------------->| | | 1502 * | cxedge + iListGap/2 |<-----------> | | 1503 * | nBitmapWidth | | 1504 * +--------------------------------------+ - 1505 * <--------------------------------------> 1506 * 2*cxedge + nBitmapWidth + iListGap 1507 * 1508 * Non-List 1509 * ======== 1510 * 1511 * With bitmap: 1512 * 1513 * +-----------------------------------+ ^ 1514 * | ^ | | 1515 * | | pad.cy / 2 | | nBitmapHeight + 1516 * | - | | szText.cy + 1517 * | +------------+ | | DEFPAD_CY + 1 1518 * | centered | Bitmap | | | 1519 * |<----------------->| | | | 1520 * | +------------+ | | 1521 * | ^ | | 1522 * | 1 | | | 1523 * | - | | 1524 * | centered +---------------+ | | 1525 * |<--------------->| Text | | | 1526 * | +---------------+ | | 1527 * +-----------------------------------+ - 1528 * <-----------------------------------> 1529 * pad.cx + max(nBitmapWidth, szText.cx) 1530 * 1531 * Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0): 1532 * 1533 * +---------------------------------------+ ^ 1534 * | ^ | | 1535 * | | 2 + pad.cy / 2 | | 1536 * | - | | szText.cy + 1537 * | centered +-----------------+ | | pad.cy + 2 1538 * |<--------------->| Text | | | 1539 * | +-----------------+ | | 1540 * | | | 1541 * +---------------------------------------+ - 1542 * <---------------------------------------> 1543 * 2*cxedge + pad.cx + szText.cx 1544 * 1545 * Without text: 1546 * As for with bitmaps, but with szText.cx zero. 1547 */ 1548 static inline SIZE TOOLBAR_MeasureButton(const TOOLBAR_INFO *infoPtr, SIZE sizeString, 1549 BOOL bHasBitmap, BOOL bValidImageList) 1550 { 1551 SIZE sizeButton; 1552 if (infoPtr->dwStyle & TBSTYLE_LIST) 1553 { 1554 /* set button height from bitmap / text height... */ 1555 sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0), 1556 sizeString.cy); 1557 1558 /* ... add on the necessary padding */ 1559 if (bValidImageList) 1560 { 1561 sizeButton.cy += infoPtr->szPadding.cy; 1562 if (!bHasBitmap) 1563 sizeButton.cy += LISTPAD_CY; 1564 } 1565 else 1566 sizeButton.cy += infoPtr->szPadding.cy; 1567 1568 /* calculate button width */ 1569 sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + 1570 infoPtr->nBitmapWidth + infoPtr->iListGap; 1571 if (sizeString.cx > 0) 1572 sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx; 1573 1574 } 1575 else 1576 { 1577 if (bHasBitmap) 1578 { 1579 sizeButton.cy = infoPtr->nBitmapHeight + infoPtr->szPadding.cy; 1580 if (sizeString.cy > 0) 1581 sizeButton.cy += 1 + sizeString.cy; 1582 sizeButton.cx = infoPtr->szPadding.cx + 1583 max(sizeString.cx, infoPtr->nBitmapWidth); 1584 } 1585 else 1586 { 1587 sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy + 1588 NONLIST_NOTEXT_OFFSET; 1589 sizeButton.cx = infoPtr->szPadding.cx + 1590 max(2*GetSystemMetrics(SM_CXEDGE) + sizeString.cx, infoPtr->nBitmapWidth); 1591 } 1592 } 1593 return sizeButton; 1594 } 1595 1596 1597 /*********************************************************************** 1598 * TOOLBAR_CalcToolbar 1599 * 1600 * This function calculates button and separator placement. It first 1601 * calculates the button sizes, gets the toolbar window width and then 1602 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap 1603 * on. It assigns a new location to each item and sends this location to 1604 * the tooltip window if appropriate. Finally, it updates the rcBound 1605 * rect and calculates the new required toolbar window height. 1606 */ 1607 static void 1608 TOOLBAR_CalcToolbar (TOOLBAR_INFO *infoPtr) 1609 { 1610 SIZE sizeString, sizeButton; 1611 BOOL validImageList = FALSE; 1612 1613 TOOLBAR_CalcStrings (infoPtr, &sizeString); 1614 1615 TOOLBAR_DumpToolbar (infoPtr, __LINE__); 1616 1617 if (TOOLBAR_IsValidImageList(infoPtr, 0)) 1618 validImageList = TRUE; 1619 sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, TRUE, validImageList); 1620 infoPtr->nButtonWidth = sizeButton.cx; 1621 infoPtr->nButtonHeight = sizeButton.cy; 1622 infoPtr->iTopMargin = default_top_margin(infoPtr); 1623 1624 if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin ) 1625 infoPtr->nButtonWidth = infoPtr->cxMin; 1626 if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax ) 1627 infoPtr->nButtonWidth = infoPtr->cxMax; 1628 1629 TOOLBAR_LayoutToolbar(infoPtr); 1630 } 1631 1632 static void 1633 TOOLBAR_LayoutToolbar(TOOLBAR_INFO *infoPtr) 1634 { 1635 TBUTTON_INFO *btnPtr; 1636 SIZE sizeButton; 1637 INT i, nRows, nSepRows; 1638 INT x, y, cx, cy; 1639 BOOL bWrap; 1640 BOOL validImageList = TOOLBAR_IsValidImageList(infoPtr, 0); 1641 BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle); 1642 1643 TOOLBAR_WrapToolbar(infoPtr); 1644 1645 x = infoPtr->nIndent; 1646 y = infoPtr->iTopMargin; 1647 cx = infoPtr->nButtonWidth; 1648 cy = infoPtr->nButtonHeight; 1649 1650 nRows = nSepRows = 0; 1651 1652 infoPtr->rcBound.top = y; 1653 infoPtr->rcBound.left = x; 1654 infoPtr->rcBound.bottom = y + cy; 1655 infoPtr->rcBound.right = x; 1656 1657 btnPtr = infoPtr->buttons; 1658 1659 TRACE("cy=%d\n", cy); 1660 1661 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) 1662 { 1663 bWrap = FALSE; 1664 if (btnPtr->fsState & TBSTATE_HIDDEN) 1665 { 1666 SetRectEmpty(&btnPtr->rect); 1667 continue; 1668 } 1669 1670 cy = infoPtr->nButtonHeight; 1671 1672 if (btnPtr->fsStyle & BTNS_SEP) 1673 { 1674 if (infoPtr->dwStyle & CCS_VERT) 1675 { 1676 cy = (btnPtr->iBitmap > 0) ? btnPtr->iBitmap : SEPARATOR_WIDTH; 1677 cx = (btnPtr->cx > 0) ? btnPtr->cx : infoPtr->nButtonWidth; 1678 } 1679 else 1680 { 1681 cx = (btnPtr->cx > 0) ? btnPtr->cx : 1682 (btnPtr->iBitmap > 0) ? btnPtr->iBitmap : SEPARATOR_WIDTH; 1683 } 1684 } 1685 else 1686 { 1687 if (btnPtr->cx) 1688 { 1689 cx = btnPtr->cx; 1690 } 1691 else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 1692 (btnPtr->fsStyle & BTNS_AUTOSIZE)) 1693 { 1694 SIZE sz; 1695 HDC hdc; 1696 HFONT hOldFont; 1697 1698 hdc = GetDC(infoPtr->hwndSelf); 1699 hOldFont = SelectObject(hdc, infoPtr->hFont); 1700 1701 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); 1702 1703 SelectObject(hdc, hOldFont); 1704 ReleaseDC(infoPtr->hwndSelf, hdc); 1705 1706 sizeButton = TOOLBAR_MeasureButton(infoPtr, sz, 1707 TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap), 1708 validImageList); 1709 cx = sizeButton.cx; 1710 } 1711 else 1712 cx = infoPtr->nButtonWidth; 1713 1714 /* if size has been set manually then don't add on extra space 1715 * for the drop down arrow */ 1716 if (!btnPtr->cx && hasDropDownArrows && 1717 ((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN))) 1718 cx += DDARROW_WIDTH; 1719 } 1720 if (btnPtr->fsState & TBSTATE_WRAP) 1721 bWrap = TRUE; 1722 1723 SetRect(&btnPtr->rect, x, y, x + cx, y + cy); 1724 1725 if (infoPtr->rcBound.left > x) 1726 infoPtr->rcBound.left = x; 1727 if (infoPtr->rcBound.right < x + cx) 1728 infoPtr->rcBound.right = x + cx; 1729 if (infoPtr->rcBound.bottom < y + cy) 1730 infoPtr->rcBound.bottom = y + cy; 1731 1732 TOOLBAR_TooltipSetRect(infoPtr, btnPtr); 1733 1734 /* btnPtr->nRow is zero based. The space between the rows is */ 1735 /* also considered as a row. */ 1736 btnPtr->nRow = nRows + nSepRows; 1737 1738 TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n", 1739 i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow, 1740 x, y, x + cx, y + cy); 1741 1742 if (bWrap) 1743 { 1744 if (!(btnPtr->fsStyle & BTNS_SEP)) 1745 y += cy; 1746 else 1747 { 1748 if (!(infoPtr->dwStyle & CCS_VERT)) 1749 y += cy + ((btnPtr->cx > 0) ? 1750 btnPtr->cx : SEPARATOR_WIDTH) * 2 / 3; 1751 else 1752 y += cy; 1753 1754 /* nSepRows is used to calculate the extra height following */ 1755 /* the last row. */ 1756 nSepRows++; 1757 } 1758 x = infoPtr->nIndent; 1759 1760 /* Increment row number unless this is the last button */ 1761 /* and it has Wrap set. */ 1762 if (i != infoPtr->nNumButtons - 1) 1763 nRows++; 1764 } 1765 else 1766 x += cx; 1767 } 1768 1769 /* infoPtr->nRows is the number of rows on the toolbar */ 1770 infoPtr->nRows = nRows + nSepRows + 1; 1771 1772 TRACE("toolbar button width %d\n", infoPtr->nButtonWidth); 1773 } 1774 1775 1776 static INT 1777 TOOLBAR_InternalHitTest (const TOOLBAR_INFO *infoPtr, const POINT *lpPt, BOOL *button) 1778 { 1779 TBUTTON_INFO *btnPtr; 1780 INT i; 1781 1782 if (button) 1783 *button = FALSE; 1784 1785 btnPtr = infoPtr->buttons; 1786 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 1787 if (btnPtr->fsState & TBSTATE_HIDDEN) 1788 continue; 1789 1790 if (btnPtr->fsStyle & BTNS_SEP) { 1791 if (PtInRect (&btnPtr->rect, *lpPt)) { 1792 TRACE(" ON SEPARATOR %d!\n", i); 1793 return -i; 1794 } 1795 } 1796 else { 1797 if (PtInRect (&btnPtr->rect, *lpPt)) { 1798 TRACE(" ON BUTTON %d!\n", i); 1799 if (button) 1800 *button = TRUE; 1801 return i; 1802 } 1803 } 1804 } 1805 1806 TRACE(" NOWHERE!\n"); 1807 return TOOLBAR_NOWHERE; 1808 } 1809 1810 1811 /* worker for TB_ADDBUTTONS and TB_INSERTBUTTON */ 1812 static BOOL 1813 TOOLBAR_InternalInsertButtonsT(TOOLBAR_INFO *infoPtr, INT iIndex, UINT nAddButtons, const TBBUTTON *lpTbb, BOOL fUnicode) 1814 { 1815 INT nOldButtons, nNewButtons, iButton; 1816 BOOL fHasString = FALSE; 1817 1818 if (iIndex < 0) /* iIndex can be negative, what means adding at the end */ 1819 iIndex = infoPtr->nNumButtons; 1820 1821 nOldButtons = infoPtr->nNumButtons; 1822 nNewButtons = nOldButtons + nAddButtons; 1823 1824 infoPtr->buttons = ReAlloc(infoPtr->buttons, sizeof(TBUTTON_INFO)*nNewButtons); 1825 memmove(&infoPtr->buttons[iIndex + nAddButtons], &infoPtr->buttons[iIndex], 1826 (nOldButtons - iIndex) * sizeof(TBUTTON_INFO)); 1827 infoPtr->nNumButtons += nAddButtons; 1828 1829 /* insert new buttons data */ 1830 for (iButton = 0; iButton < nAddButtons; iButton++) { 1831 TBUTTON_INFO *btnPtr = &infoPtr->buttons[iIndex + iButton]; 1832 1833 TOOLBAR_DumpTBButton(lpTbb + iButton, fUnicode); 1834 1835 ZeroMemory(btnPtr, sizeof(*btnPtr)); 1836 1837 btnPtr->iBitmap = lpTbb[iButton].iBitmap; 1838 btnPtr->idCommand = lpTbb[iButton].idCommand; 1839 btnPtr->fsState = lpTbb[iButton].fsState; 1840 btnPtr->fsStyle = lpTbb[iButton].fsStyle; 1841 btnPtr->dwData = lpTbb[iButton].dwData; 1842 if (btnPtr->fsStyle & BTNS_SEP) 1843 btnPtr->iString = -1; 1844 else if(!IS_INTRESOURCE(lpTbb[iButton].iString) && lpTbb[iButton].iString != -1) 1845 { 1846 if (fUnicode) 1847 Str_SetPtrW((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[iButton].iString ); 1848 else 1849 Str_SetPtrAtoW((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[iButton].iString); 1850 fHasString = TRUE; 1851 } 1852 else 1853 btnPtr->iString = lpTbb[iButton].iString; 1854 1855 TOOLBAR_TooltipAddTool(infoPtr, btnPtr); 1856 } 1857 1858 if (infoPtr->nNumStrings > 0 || fHasString) 1859 TOOLBAR_CalcToolbar(infoPtr); 1860 else 1861 TOOLBAR_LayoutToolbar(infoPtr); 1862 TOOLBAR_AutoSize(infoPtr); 1863 1864 TOOLBAR_DumpToolbar(infoPtr, __LINE__); 1865 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 1866 return TRUE; 1867 } 1868 1869 1870 static INT 1871 TOOLBAR_GetButtonIndex (const TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex) 1872 { 1873 TBUTTON_INFO *btnPtr; 1874 INT i; 1875 1876 if (CommandIsIndex) { 1877 TRACE("command is really index command=%d\n", idCommand); 1878 if (idCommand >= infoPtr->nNumButtons) return -1; 1879 return idCommand; 1880 } 1881 btnPtr = infoPtr->buttons; 1882 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 1883 if (btnPtr->idCommand == idCommand) { 1884 TRACE("command=%d index=%d\n", idCommand, i); 1885 return i; 1886 } 1887 } 1888 TRACE("no index found for command=%d\n", idCommand); 1889 return -1; 1890 } 1891 1892 1893 static INT 1894 TOOLBAR_GetCheckedGroupButtonIndex (const TOOLBAR_INFO *infoPtr, INT nIndex) 1895 { 1896 TBUTTON_INFO *btnPtr; 1897 INT nRunIndex; 1898 1899 if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons)) 1900 return -1; 1901 1902 /* check index button */ 1903 btnPtr = &infoPtr->buttons[nIndex]; 1904 if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { 1905 if (btnPtr->fsState & TBSTATE_CHECKED) 1906 return nIndex; 1907 } 1908 1909 /* check previous buttons */ 1910 nRunIndex = nIndex - 1; 1911 while (nRunIndex >= 0) { 1912 btnPtr = &infoPtr->buttons[nRunIndex]; 1913 if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) { 1914 if (btnPtr->fsState & TBSTATE_CHECKED) 1915 return nRunIndex; 1916 } 1917 else 1918 break; 1919 nRunIndex--; 1920 } 1921 1922 /* check next buttons */ 1923 nRunIndex = nIndex + 1; 1924 while (nRunIndex < infoPtr->nNumButtons) { 1925 btnPtr = &infoPtr->buttons[nRunIndex]; 1926 if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) { 1927 if (btnPtr->fsState & TBSTATE_CHECKED) 1928 return nRunIndex; 1929 } 1930 else 1931 break; 1932 nRunIndex++; 1933 } 1934 1935 return -1; 1936 } 1937 1938 1939 static VOID 1940 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, 1941 WPARAM wParam, LPARAM lParam) 1942 { 1943 MSG msg; 1944 1945 msg.hwnd = hwndMsg; 1946 msg.message = uMsg; 1947 msg.wParam = wParam; 1948 msg.lParam = lParam; 1949 msg.time = GetMessageTime (); 1950 msg.pt.x = (short)LOWORD(GetMessagePos ()); 1951 msg.pt.y = (short)HIWORD(GetMessagePos ()); 1952 1953 SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); 1954 } 1955 1956 1957 static LRESULT 1958 TOOLBAR_ThemeChanged(HWND hwnd) 1959 { 1960 HTHEME theme = GetWindowTheme(hwnd); 1961 CloseThemeData(theme); 1962 OpenThemeData(hwnd, themeClass); 1963 return 0; 1964 } 1965 1966 static void 1967 TOOLBAR_TooltipAddTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 1968 { 1969 if (infoPtr->hwndToolTip && !(button->fsStyle & BTNS_SEP)) { 1970 TTTOOLINFOW ti; 1971 1972 ZeroMemory(&ti, sizeof(TTTOOLINFOW)); 1973 ti.cbSize = sizeof (TTTOOLINFOW); 1974 ti.hwnd = infoPtr->hwndSelf; 1975 ti.uId = button->idCommand; 1976 ti.hinst = 0; 1977 ti.lpszText = LPSTR_TEXTCALLBACKW; 1978 /* ti.lParam = random value from the stack? */ 1979 1980 SendMessageW(infoPtr->hwndToolTip, TTM_ADDTOOLW, 1981 0, (LPARAM)&ti); 1982 } 1983 } 1984 1985 static void 1986 TOOLBAR_TooltipDelTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 1987 { 1988 if ((infoPtr->hwndToolTip) && !(button->fsStyle & BTNS_SEP)) { 1989 TTTOOLINFOW ti; 1990 1991 ZeroMemory(&ti, sizeof(ti)); 1992 ti.cbSize = sizeof(ti); 1993 ti.hwnd = infoPtr->hwndSelf; 1994 ti.uId = button->idCommand; 1995 1996 SendMessageW(infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); 1997 } 1998 } 1999 2000 static void TOOLBAR_TooltipSetRect(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 2001 { 2002 /* Set the toolTip only for non-hidden, non-separator button */ 2003 if (infoPtr->hwndToolTip && !(button->fsStyle & BTNS_SEP)) 2004 { 2005 TTTOOLINFOW ti; 2006 2007 ZeroMemory(&ti, sizeof(ti)); 2008 ti.cbSize = sizeof(ti); 2009 ti.hwnd = infoPtr->hwndSelf; 2010 ti.uId = button->idCommand; 2011 ti.rect = button->rect; 2012 SendMessageW(infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, 0, (LPARAM)&ti); 2013 } 2014 } 2015 2016 /* Creates the tooltip control */ 2017 static void 2018 TOOLBAR_TooltipCreateControl(TOOLBAR_INFO *infoPtr) 2019 { 2020 int i; 2021 NMTOOLTIPSCREATED nmttc; 2022 2023 infoPtr->hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP, 2024 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 2025 infoPtr->hwndSelf, 0, 0, 0); 2026 2027 if (!infoPtr->hwndToolTip) 2028 return; 2029 2030 /* Send NM_TOOLTIPSCREATED notification */ 2031 nmttc.hwndToolTips = infoPtr->hwndToolTip; 2032 TOOLBAR_SendNotify(&nmttc.hdr, infoPtr, NM_TOOLTIPSCREATED); 2033 2034 for (i = 0; i < infoPtr->nNumButtons; i++) 2035 { 2036 TOOLBAR_TooltipAddTool(infoPtr, &infoPtr->buttons[i]); 2037 TOOLBAR_TooltipSetRect(infoPtr, &infoPtr->buttons[i]); 2038 } 2039 } 2040 2041 /* keeps available button list box sorted by button id */ 2042 static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew) 2043 { 2044 int i; 2045 int count; 2046 PCUSTOMBUTTON btnInfo; 2047 HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 2048 2049 TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand); 2050 2051 count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); 2052 2053 /* position 0 is always separator */ 2054 for (i = 1; i < count; i++) 2055 { 2056 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, i, 0); 2057 if (btnInfoNew->btn.idCommand < btnInfo->btn.idCommand) 2058 { 2059 i = SendMessageW(hwndAvail, LB_INSERTSTRING, i, 0); 2060 SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); 2061 return; 2062 } 2063 } 2064 /* id higher than all others add to end */ 2065 i = SendMessageW(hwndAvail, LB_ADDSTRING, 0, 0); 2066 SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); 2067 } 2068 2069 static void TOOLBAR_Cust_MoveButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT nIndexFrom, INT nIndexTo) 2070 { 2071 NMTOOLBARW nmtb; 2072 2073 TRACE("index from %d, index to %d\n", nIndexFrom, nIndexTo); 2074 2075 if (nIndexFrom == nIndexTo) 2076 return; 2077 2078 /* MSDN states that iItem is the index of the button, rather than the 2079 * command ID as used by every other NMTOOLBAR notification */ 2080 nmtb.iItem = nIndexFrom; 2081 if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) 2082 { 2083 PCUSTOMBUTTON btnInfo; 2084 NMHDR hdr; 2085 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 2086 int count = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2087 2088 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, nIndexFrom, 0); 2089 2090 SendMessageW(hwndList, LB_DELETESTRING, nIndexFrom, 0); 2091 SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); 2092 SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); 2093 SendMessageW(hwndList, LB_SETCURSEL, nIndexTo, 0); 2094 2095 if (nIndexTo <= 0) 2096 EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), FALSE); 2097 else 2098 EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), TRUE); 2099 2100 /* last item is always separator, so -2 instead of -1 */ 2101 if (nIndexTo >= (count - 2)) 2102 EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), FALSE); 2103 else 2104 EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), TRUE); 2105 2106 SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, nIndexFrom, 0); 2107 SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); 2108 2109 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 2110 } 2111 } 2112 2113 static void TOOLBAR_Cust_AddButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT nIndexAvail, INT nIndexTo) 2114 { 2115 NMTOOLBARW nmtb; 2116 2117 TRACE("Add: nIndexAvail %d, nIndexTo %d\n", nIndexAvail, nIndexTo); 2118 2119 /* MSDN states that iItem is the index of the button, rather than the 2120 * command ID as used by every other NMTOOLBAR notification */ 2121 nmtb.iItem = nIndexAvail; 2122 if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) 2123 { 2124 PCUSTOMBUTTON btnInfo; 2125 NMHDR hdr; 2126 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 2127 HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 2128 int count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); 2129 2130 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, nIndexAvail, 0); 2131 2132 if (nIndexAvail != 0) /* index == 0 indicates separator */ 2133 { 2134 /* remove from 'available buttons' list */ 2135 SendMessageW(hwndAvail, LB_DELETESTRING, nIndexAvail, 0); 2136 if (nIndexAvail == count-1) 2137 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail-1 , 0); 2138 else 2139 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail , 0); 2140 } 2141 else 2142 { 2143 PCUSTOMBUTTON btnNew; 2144 2145 /* duplicate 'separator' button */ 2146 btnNew = Alloc(sizeof(CUSTOMBUTTON)); 2147 *btnNew = *btnInfo; 2148 btnInfo = btnNew; 2149 } 2150 2151 /* insert into 'toolbar button' list */ 2152 SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); 2153 SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); 2154 2155 SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); 2156 2157 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 2158 } 2159 } 2160 2161 static void TOOLBAR_Cust_RemoveButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT index) 2162 { 2163 PCUSTOMBUTTON btnInfo; 2164 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 2165 2166 TRACE("Remove: index %d\n", index); 2167 2168 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, index, 0); 2169 2170 /* send TBN_QUERYDELETE notification */ 2171 if (TOOLBAR_IsButtonRemovable(custInfo->tbInfo, index, btnInfo)) 2172 { 2173 NMHDR hdr; 2174 2175 SendMessageW(hwndList, LB_DELETESTRING, index, 0); 2176 SendMessageW(hwndList, LB_SETCURSEL, index , 0); 2177 2178 SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, index, 0); 2179 2180 /* insert into 'available button' list */ 2181 if (!(btnInfo->btn.fsStyle & BTNS_SEP)) 2182 TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); 2183 else 2184 Free(btnInfo); 2185 2186 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 2187 } 2188 } 2189 2190 /* drag list notification function for toolbar buttons list box */ 2191 static LRESULT TOOLBAR_Cust_ToolbarDragListNotification(const CUSTDLG_INFO *custInfo, HWND hwnd, 2192 const DRAGLISTINFO *pDLI) 2193 { 2194 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 2195 switch (pDLI->uNotification) 2196 { 2197 case DL_BEGINDRAG: 2198 { 2199 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 2200 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2201 /* no dragging for last item (separator) */ 2202 if (nCurrentItem >= (nCount - 1)) return FALSE; 2203 return TRUE; 2204 } 2205 case DL_DRAGGING: 2206 { 2207 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 2208 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2209 /* no dragging past last item (separator) */ 2210 if ((nCurrentItem >= 0) && (nCurrentItem < (nCount - 1))) 2211 { 2212 DrawInsert(hwnd, hwndList, nCurrentItem); 2213 /* FIXME: native uses "move button" cursor */ 2214 return DL_COPYCURSOR; 2215 } 2216 2217 /* not over toolbar buttons list */ 2218 if (nCurrentItem < 0) 2219 { 2220 POINT ptWindow = pDLI->ptCursor; 2221 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 2222 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 2223 /* over available buttons list? */ 2224 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 2225 /* FIXME: native uses "move button" cursor */ 2226 return DL_COPYCURSOR; 2227 } 2228 /* clear drag arrow */ 2229 DrawInsert(hwnd, hwndList, -1); 2230 return DL_STOPCURSOR; 2231 } 2232 case DL_DROPPED: 2233 { 2234 INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 2235 INT nIndexFrom = SendMessageW(hwndList, LB_GETCURSEL, 0, 0); 2236 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2237 if ((nIndexTo >= 0) && (nIndexTo < (nCount - 1))) 2238 { 2239 /* clear drag arrow */ 2240 DrawInsert(hwnd, hwndList, -1); 2241 /* move item */ 2242 TOOLBAR_Cust_MoveButton(custInfo, hwnd, nIndexFrom, nIndexTo); 2243 } 2244 /* not over toolbar buttons list */ 2245 if (nIndexTo < 0) 2246 { 2247 POINT ptWindow = pDLI->ptCursor; 2248 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 2249 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 2250 /* over available buttons list? */ 2251 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 2252 TOOLBAR_Cust_RemoveButton(custInfo, hwnd, nIndexFrom); 2253 } 2254 break; 2255 } 2256 case DL_CANCELDRAG: 2257 /* Clear drag arrow */ 2258 DrawInsert(hwnd, hwndList, -1); 2259 break; 2260 } 2261 2262 return 0; 2263 } 2264 2265 /* drag list notification function for available buttons list box */ 2266 static LRESULT TOOLBAR_Cust_AvailDragListNotification(const CUSTDLG_INFO *custInfo, HWND hwnd, 2267 const DRAGLISTINFO *pDLI) 2268 { 2269 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 2270 switch (pDLI->uNotification) 2271 { 2272 case DL_BEGINDRAG: 2273 return TRUE; 2274 case DL_DRAGGING: 2275 { 2276 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 2277 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2278 /* no dragging past last item (separator) */ 2279 if ((nCurrentItem >= 0) && (nCurrentItem < nCount)) 2280 { 2281 DrawInsert(hwnd, hwndList, nCurrentItem); 2282 /* FIXME: native uses "move button" cursor */ 2283 return DL_COPYCURSOR; 2284 } 2285 2286 /* not over toolbar buttons list */ 2287 if (nCurrentItem < 0) 2288 { 2289 POINT ptWindow = pDLI->ptCursor; 2290 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 2291 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 2292 /* over available buttons list? */ 2293 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 2294 /* FIXME: native uses "move button" cursor */ 2295 return DL_COPYCURSOR; 2296 } 2297 /* clear drag arrow */ 2298 DrawInsert(hwnd, hwndList, -1); 2299 return DL_STOPCURSOR; 2300 } 2301 case DL_DROPPED: 2302 { 2303 INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 2304 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 2305 INT nIndexFrom = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); 2306 if ((nIndexTo >= 0) && (nIndexTo < nCount)) 2307 { 2308 /* clear drag arrow */ 2309 DrawInsert(hwnd, hwndList, -1); 2310 /* add item */ 2311 TOOLBAR_Cust_AddButton(custInfo, hwnd, nIndexFrom, nIndexTo); 2312 } 2313 } 2314 case DL_CANCELDRAG: 2315 /* Clear drag arrow */ 2316 DrawInsert(hwnd, hwndList, -1); 2317 break; 2318 } 2319 return 0; 2320 } 2321 2322 extern UINT uDragListMessage DECLSPEC_HIDDEN; 2323 2324 /*********************************************************************** 2325 * TOOLBAR_CustomizeDialogProc 2326 * This function implements the toolbar customization dialog. 2327 */ 2328 static INT_PTR CALLBACK 2329 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 2330 { 2331 PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongPtrW (hwnd, DWLP_USER); 2332 PCUSTOMBUTTON btnInfo; 2333 NMTOOLBARA nmtb; 2334 TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL; 2335 2336 switch (uMsg) 2337 { 2338 case WM_INITDIALOG: 2339 custInfo = (PCUSTDLG_INFO)lParam; 2340 SetWindowLongPtrW (hwnd, DWLP_USER, (LONG_PTR)custInfo); 2341 2342 if (custInfo) 2343 { 2344 WCHAR Buffer[256]; 2345 int i = 0; 2346 int index; 2347 NMTBINITCUSTOMIZE nmtbic; 2348 2349 infoPtr = custInfo->tbInfo; 2350 2351 /* send TBN_QUERYINSERT notification */ 2352 nmtb.iItem = custInfo->tbInfo->nNumButtons; 2353 2354 if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT)) 2355 return FALSE; 2356 2357 nmtbic.hwndDialog = hwnd; 2358 /* Send TBN_INITCUSTOMIZE notification */ 2359 if (TOOLBAR_SendNotify (&nmtbic.hdr, infoPtr, TBN_INITCUSTOMIZE) == 2360 TBNRF_HIDEHELP) 2361 { 2362 TRACE("TBNRF_HIDEHELP requested\n"); 2363 ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE); 2364 } 2365 2366 /* add items to 'toolbar buttons' list and check if removable */ 2367 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++) 2368 { 2369 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 2370 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 2371 btnInfo->btn.fsStyle = BTNS_SEP; 2372 btnInfo->bVirtual = FALSE; 2373 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 2374 2375 /* send TBN_QUERYDELETE notification */ 2376 btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo); 2377 2378 index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0); 2379 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 2380 } 2381 2382 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); 2383 2384 /* insert separator button into 'available buttons' list */ 2385 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 2386 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 2387 btnInfo->btn.fsStyle = BTNS_SEP; 2388 btnInfo->bVirtual = FALSE; 2389 btnInfo->bRemovable = TRUE; 2390 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 2391 index = (int)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); 2392 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 2393 2394 /* insert all buttons into dsa */ 2395 for (i = 0;; i++) 2396 { 2397 /* send TBN_GETBUTTONINFO notification */ 2398 NMTOOLBARW nmtb; 2399 nmtb.iItem = i; 2400 nmtb.pszText = Buffer; 2401 nmtb.cchText = 256; 2402 2403 /* Clear previous button's text */ 2404 ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR)); 2405 2406 if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb)) 2407 break; 2408 2409 TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%ld) %s\n", 2410 nmtb.tbButton.fsStyle, i, 2411 nmtb.tbButton.idCommand, 2412 nmtb.tbButton.iString, 2413 nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString]) 2414 : ""); 2415 2416 /* insert button into the appropriate list */ 2417 index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE); 2418 if (index == -1) 2419 { 2420 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 2421 btnInfo->bVirtual = FALSE; 2422 btnInfo->bRemovable = TRUE; 2423 } 2424 else 2425 { 2426 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, 2427 IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); 2428 } 2429 2430 btnInfo->btn = nmtb.tbButton; 2431 if (!(nmtb.tbButton.fsStyle & BTNS_SEP)) 2432 { 2433 if (lstrlenW(nmtb.pszText)) 2434 lstrcpyW(btnInfo->text, nmtb.pszText); 2435 else if (nmtb.tbButton.iString >= 0 && 2436 nmtb.tbButton.iString < infoPtr->nNumStrings) 2437 { 2438 lstrcpyW(btnInfo->text, 2439 infoPtr->strings[nmtb.tbButton.iString]); 2440 } 2441 } 2442 2443 if (index == -1) 2444 TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); 2445 } 2446 2447 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); 2448 2449 /* select first item in the 'available' list */ 2450 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0); 2451 2452 /* append 'virtual' separator button to the 'toolbar buttons' list */ 2453 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 2454 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 2455 btnInfo->btn.fsStyle = BTNS_SEP; 2456 btnInfo->bVirtual = TRUE; 2457 btnInfo->bRemovable = FALSE; 2458 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 2459 index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); 2460 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 2461 2462 /* select last item in the 'toolbar' list */ 2463 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0); 2464 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0); 2465 2466 MakeDragList(GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX)); 2467 MakeDragList(GetDlgItem(hwnd, IDC_AVAILBTN_LBOX)); 2468 2469 /* set focus and disable buttons */ 2470 PostMessageW (hwnd, WM_USER, 0, 0); 2471 } 2472 return TRUE; 2473 2474 case WM_USER: 2475 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 2476 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 2477 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE); 2478 SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX)); 2479 return TRUE; 2480 2481 case WM_CLOSE: 2482 EndDialog(hwnd, FALSE); 2483 return TRUE; 2484 2485 case WM_COMMAND: 2486 switch (LOWORD(wParam)) 2487 { 2488 case IDC_TOOLBARBTN_LBOX: 2489 if (HIWORD(wParam) == LBN_SELCHANGE) 2490 { 2491 PCUSTOMBUTTON btnInfo; 2492 NMTOOLBARA nmtb; 2493 int count; 2494 int index; 2495 2496 count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); 2497 index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 2498 2499 /* send TBN_QUERYINSERT notification */ 2500 nmtb.iItem = index; 2501 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT); 2502 2503 /* get list box item */ 2504 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); 2505 2506 if (index == (count - 1)) 2507 { 2508 /* last item (virtual separator) */ 2509 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 2510 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 2511 } 2512 else if (index == (count - 2)) 2513 { 2514 /* second last item (last non-virtual item) */ 2515 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); 2516 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 2517 } 2518 else if (index == 0) 2519 { 2520 /* first item */ 2521 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 2522 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); 2523 } 2524 else 2525 { 2526 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); 2527 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); 2528 } 2529 2530 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable); 2531 } 2532 break; 2533 2534 case IDC_MOVEUP_BTN: 2535 { 2536 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 2537 TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index-1); 2538 } 2539 break; 2540 2541 case IDC_MOVEDN_BTN: /* move down */ 2542 { 2543 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 2544 TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index+1); 2545 } 2546 break; 2547 2548 case IDC_REMOVE_BTN: /* remove button */ 2549 { 2550 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 2551 2552 if (LB_ERR == index) 2553 break; 2554 2555 TOOLBAR_Cust_RemoveButton(custInfo, hwnd, index); 2556 } 2557 break; 2558 case IDC_HELP_BTN: 2559 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP); 2560 break; 2561 case IDC_RESET_BTN: 2562 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET); 2563 break; 2564 2565 case IDOK: /* Add button */ 2566 { 2567 int index; 2568 int indexto; 2569 2570 index = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); 2571 indexto = SendDlgItemMessageW(hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 2572 2573 TOOLBAR_Cust_AddButton(custInfo, hwnd, index, indexto); 2574 } 2575 break; 2576 2577 case IDCANCEL: 2578 EndDialog(hwnd, FALSE); 2579 break; 2580 } 2581 return TRUE; 2582 2583 case WM_DESTROY: 2584 { 2585 int count; 2586 int i; 2587 2588 /* delete items from 'toolbar buttons' listbox*/ 2589 count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); 2590 for (i = 0; i < count; i++) 2591 { 2592 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0); 2593 Free(btnInfo); 2594 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0); 2595 } 2596 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0); 2597 2598 2599 /* delete items from 'available buttons' listbox*/ 2600 count = SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0); 2601 for (i = 0; i < count; i++) 2602 { 2603 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0); 2604 Free(btnInfo); 2605 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0); 2606 } 2607 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0); 2608 } 2609 return TRUE; 2610 2611 case WM_DRAWITEM: 2612 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) 2613 { 2614 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; 2615 RECT rcButton; 2616 RECT rcText; 2617 HPEN hPen, hOldPen; 2618 HBRUSH hOldBrush; 2619 COLORREF oldText = 0; 2620 COLORREF oldBk = 0; 2621 2622 /* get item data */ 2623 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, wParam, LB_GETITEMDATA, lpdis->itemID, 0); 2624 if (btnInfo == NULL) 2625 { 2626 FIXME("btnInfo invalid!\n"); 2627 return TRUE; 2628 } 2629 2630 /* set colors and select objects */ 2631 oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow); 2632 if (btnInfo->bVirtual) 2633 oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText); 2634 else 2635 oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText); 2636 hPen = CreatePen( PS_SOLID, 1, 2637 (lpdis->itemState & ODS_SELECTED)?comctl32_color.clrHighlight:comctl32_color.clrWindow); 2638 hOldPen = SelectObject (lpdis->hDC, hPen ); 2639 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW)); 2640 2641 /* fill background rectangle */ 2642 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, 2643 lpdis->rcItem.right, lpdis->rcItem.bottom); 2644 2645 /* calculate button and text rectangles */ 2646 CopyRect (&rcButton, &lpdis->rcItem); 2647 InflateRect (&rcButton, -1, -1); 2648 CopyRect (&rcText, &rcButton); 2649 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6; 2650 rcText.left = rcButton.right + 2; 2651 2652 /* draw focus rectangle */ 2653 if (lpdis->itemState & ODS_FOCUS) 2654 DrawFocusRect (lpdis->hDC, &lpdis->rcItem); 2655 2656 /* draw button */ 2657 if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) 2658 DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT); 2659 2660 /* draw image and text */ 2661 if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) { 2662 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, 2663 btnInfo->btn.iBitmap)); 2664 ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap), 2665 lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL); 2666 } 2667 DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText, 2668 DT_LEFT | DT_VCENTER | DT_SINGLELINE); 2669 2670 /* delete objects and reset colors */ 2671 SelectObject (lpdis->hDC, hOldBrush); 2672 SelectObject (lpdis->hDC, hOldPen); 2673 SetBkColor (lpdis->hDC, oldBk); 2674 SetTextColor (lpdis->hDC, oldText); 2675 DeleteObject( hPen ); 2676 return TRUE; 2677 } 2678 return FALSE; 2679 2680 case WM_MEASUREITEM: 2681 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) 2682 { 2683 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam; 2684 2685 lpmis->itemHeight = 15 + 8; /* default height */ 2686 2687 return TRUE; 2688 } 2689 return FALSE; 2690 2691 default: 2692 if (uDragListMessage && (uMsg == uDragListMessage)) 2693 { 2694 if (wParam == IDC_TOOLBARBTN_LBOX) 2695 { 2696 LRESULT res = TOOLBAR_Cust_ToolbarDragListNotification( 2697 custInfo, hwnd, (DRAGLISTINFO *)lParam); 2698 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); 2699 return TRUE; 2700 } 2701 else if (wParam == IDC_AVAILBTN_LBOX) 2702 { 2703 LRESULT res = TOOLBAR_Cust_AvailDragListNotification( 2704 custInfo, hwnd, (DRAGLISTINFO *)lParam); 2705 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); 2706 return TRUE; 2707 } 2708 } 2709 return FALSE; 2710 } 2711 } 2712 2713 static BOOL 2714 TOOLBAR_AddBitmapToImageList(TOOLBAR_INFO *infoPtr, HIMAGELIST himlDef, const TBITMAP_INFO *bitmap) 2715 { 2716 HBITMAP hbmLoad; 2717 INT nCountBefore = ImageList_GetImageCount(himlDef); 2718 INT nCountAfter; 2719 INT cxIcon, cyIcon; 2720 INT nAdded; 2721 INT nIndex; 2722 2723 TRACE("adding hInst=%p nID=%d nButtons=%d\n", bitmap->hInst, bitmap->nID, bitmap->nButtons); 2724 /* Add bitmaps to the default image list */ 2725 if (bitmap->hInst == NULL) /* a handle was passed */ 2726 hbmLoad = CopyImage(ULongToHandle(bitmap->nID), IMAGE_BITMAP, 0, 0, 0); 2727 else if (bitmap->hInst == COMCTL32_hModule) 2728 hbmLoad = LoadImageW( bitmap->hInst, MAKEINTRESOURCEW(bitmap->nID), 2729 IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); 2730 else 2731 hbmLoad = CreateMappedBitmap(bitmap->hInst, bitmap->nID, 0, NULL, 0); 2732 2733 /* enlarge the bitmap if needed */ 2734 ImageList_GetIconSize(himlDef, &cxIcon, &cyIcon); 2735 if (bitmap->hInst != COMCTL32_hModule) 2736 COMCTL32_EnsureBitmapSize(&hbmLoad, cxIcon*(INT)bitmap->nButtons, cyIcon, comctl32_color.clrBtnFace); 2737 2738 nIndex = ImageList_AddMasked(himlDef, hbmLoad, comctl32_color.clrBtnFace); 2739 DeleteObject(hbmLoad); 2740 if (nIndex == -1) 2741 return FALSE; 2742 2743 nCountAfter = ImageList_GetImageCount(himlDef); 2744 nAdded = nCountAfter - nCountBefore; 2745 if (bitmap->nButtons == 0) /* wParam == 0 is special and means add only one image */ 2746 { 2747 ImageList_SetImageCount(himlDef, nCountBefore + 1); 2748 } else if (nAdded > (INT)bitmap->nButtons) { 2749 TRACE("Added more images than wParam: Previous image number %i added %i while wParam %i. Images in list %i\n", 2750 nCountBefore, nAdded, bitmap->nButtons, nCountAfter); 2751 } 2752 2753 infoPtr->nNumBitmaps += nAdded; 2754 return TRUE; 2755 } 2756 2757 static void 2758 TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr) 2759 { 2760 HIMAGELIST himlDef; 2761 HIMAGELIST himlNew; 2762 INT cx, cy; 2763 INT i; 2764 2765 himlDef = GETDEFIMAGELIST(infoPtr, 0); 2766 if (himlDef == NULL || himlDef != infoPtr->himlInt) 2767 return; 2768 if (!ImageList_GetIconSize(himlDef, &cx, &cy)) 2769 return; 2770 if (cx == infoPtr->nBitmapWidth && cy == infoPtr->nBitmapHeight) 2771 return; 2772 2773 TRACE("Update icon size: %dx%d -> %dx%d\n", 2774 cx, cy, infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 2775 2776 himlNew = ImageList_Create(infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, 2777 ILC_COLOR32|ILC_MASK, 8, 2); 2778 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) 2779 TOOLBAR_AddBitmapToImageList(infoPtr, himlNew, &infoPtr->bitmaps[i]); 2780 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlNew, 0); 2781 infoPtr->himlInt = himlNew; 2782 2783 infoPtr->nNumBitmaps -= ImageList_GetImageCount(himlDef); 2784 ImageList_Destroy(himlDef); 2785 } 2786 2787 /*********************************************************************** 2788 * TOOLBAR_AddBitmap: Add the bitmaps to the default image list. 2789 * 2790 */ 2791 static LRESULT 2792 TOOLBAR_AddBitmap (TOOLBAR_INFO *infoPtr, INT count, const TBADDBITMAP *lpAddBmp) 2793 { 2794 TBITMAP_INFO info; 2795 INT iSumButtons, i; 2796 HIMAGELIST himlDef; 2797 2798 TRACE("hwnd=%p count=%d lpAddBmp=%p\n", infoPtr->hwndSelf, count, lpAddBmp); 2799 if (!lpAddBmp) 2800 return -1; 2801 2802 if (lpAddBmp->hInst == HINST_COMMCTRL) 2803 { 2804 info.hInst = COMCTL32_hModule; 2805 switch (lpAddBmp->nID) 2806 { 2807 case IDB_STD_SMALL_COLOR: 2808 info.nButtons = 15; 2809 info.nID = IDB_STD_SMALL; 2810 break; 2811 case IDB_STD_LARGE_COLOR: 2812 info.nButtons = 15; 2813 info.nID = IDB_STD_LARGE; 2814 break; 2815 case IDB_VIEW_SMALL_COLOR: 2816 info.nButtons = 12; 2817 info.nID = IDB_VIEW_SMALL; 2818 break; 2819 case IDB_VIEW_LARGE_COLOR: 2820 info.nButtons = 12; 2821 info.nID = IDB_VIEW_LARGE; 2822 break; 2823 case IDB_HIST_SMALL_COLOR: 2824 info.nButtons = 5; 2825 info.nID = IDB_HIST_SMALL; 2826 break; 2827 case IDB_HIST_LARGE_COLOR: 2828 info.nButtons = 5; 2829 info.nID = IDB_HIST_LARGE; 2830 break; 2831 default: 2832 return -1; 2833 } 2834 2835 TRACE ("adding %d internal bitmaps!\n", info.nButtons); 2836 2837 /* Windows resize all the buttons to the size of a newly added standard image */ 2838 if (lpAddBmp->nID & 1) 2839 { 2840 /* large icons: 24x24. Will make the button 31x30 */ 2841 SendMessageW (infoPtr->hwndSelf, TB_SETBITMAPSIZE, 0, MAKELPARAM(24, 24)); 2842 } 2843 else 2844 { 2845 /* small icons: 16x16. Will make the buttons 23x22 */ 2846 SendMessageW (infoPtr->hwndSelf, TB_SETBITMAPSIZE, 0, MAKELPARAM(16, 16)); 2847 } 2848 2849 TOOLBAR_CalcToolbar (infoPtr); 2850 } 2851 else 2852 { 2853 info.nButtons = count; 2854 info.hInst = lpAddBmp->hInst; 2855 info.nID = lpAddBmp->nID; 2856 TRACE("adding %d bitmaps!\n", info.nButtons); 2857 } 2858 2859 /* check if the bitmap is already loaded and compute iSumButtons */ 2860 iSumButtons = 0; 2861 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) 2862 { 2863 if (infoPtr->bitmaps[i].hInst == info.hInst && 2864 infoPtr->bitmaps[i].nID == info.nID) 2865 return iSumButtons; 2866 iSumButtons += infoPtr->bitmaps[i].nButtons; 2867 } 2868 2869 if (!infoPtr->cimlDef) { 2870 /* create new default image list */ 2871 TRACE ("creating default image list!\n"); 2872 2873 himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, 2874 ILC_COLOR32 | ILC_MASK, info.nButtons, 2); 2875 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0); 2876 infoPtr->himlInt = himlDef; 2877 } 2878 else { 2879 himlDef = GETDEFIMAGELIST(infoPtr, 0); 2880 } 2881 2882 if (!himlDef) { 2883 WARN("No default image list available\n"); 2884 return -1; 2885 } 2886 2887 if (!TOOLBAR_AddBitmapToImageList(infoPtr, himlDef, &info)) 2888 return -1; 2889 2890 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); 2891 infoPtr->bitmaps = ReAlloc(infoPtr->bitmaps, (infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO)); 2892 infoPtr->bitmaps[infoPtr->nNumBitmapInfos] = info; 2893 infoPtr->nNumBitmapInfos++; 2894 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); 2895 2896 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 2897 return iSumButtons; 2898 } 2899 2900 2901 static LRESULT 2902 TOOLBAR_AddButtonsT(TOOLBAR_INFO *infoPtr, INT nAddButtons, const TBBUTTON* lpTbb, BOOL fUnicode) 2903 { 2904 TRACE("adding %d buttons (unicode=%d)!\n", nAddButtons, fUnicode); 2905 2906 return TOOLBAR_InternalInsertButtonsT(infoPtr, -1, nAddButtons, lpTbb, fUnicode); 2907 } 2908 2909 2910 static LRESULT 2911 TOOLBAR_AddStringW (TOOLBAR_INFO *infoPtr, HINSTANCE hInstance, LPARAM lParam) 2912 { 2913 #define MAX_RESOURCE_STRING_LENGTH 512 2914 BOOL fFirstString = (infoPtr->nNumStrings == 0); 2915 INT nIndex = infoPtr->nNumStrings; 2916 2917 TRACE("%p, %lx\n", hInstance, lParam); 2918 2919 if (IS_INTRESOURCE(lParam)) { 2920 WCHAR szString[MAX_RESOURCE_STRING_LENGTH]; 2921 WCHAR delimiter; 2922 WCHAR *next_delim; 2923 HRSRC hrsrc; 2924 WCHAR *p; 2925 INT len; 2926 2927 TRACE("adding string from resource\n"); 2928 2929 if (!hInstance) return -1; 2930 2931 hrsrc = FindResourceW( hInstance, MAKEINTRESOURCEW((LOWORD(lParam) >> 4) + 1), 2932 (LPWSTR)RT_STRING ); 2933 if (!hrsrc) 2934 { 2935 TRACE("string not found in resources\n"); 2936 return -1; 2937 } 2938 2939 len = LoadStringW (hInstance, (UINT)lParam, 2940 szString, MAX_RESOURCE_STRING_LENGTH); 2941 2942 TRACE("len=%d %s\n", len, debugstr_w(szString)); 2943 if (len == 0 || len == 1) 2944 return nIndex; 2945 2946 TRACE("delimiter: 0x%x\n", *szString); 2947 delimiter = *szString; 2948 p = szString + 1; 2949 2950 while ((next_delim = strchrW(p, delimiter)) != NULL) { 2951 *next_delim = 0; 2952 if (next_delim + 1 >= szString + len) 2953 { 2954 /* this may happen if delimiter == '\0' or if the last char is a 2955 * delimiter (then it is ignored like the native does) */ 2956 break; 2957 } 2958 2959 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 2960 Str_SetPtrW(&infoPtr->strings[infoPtr->nNumStrings], p); 2961 infoPtr->nNumStrings++; 2962 2963 p = next_delim + 1; 2964 } 2965 } 2966 else { 2967 LPWSTR p = (LPWSTR)lParam; 2968 INT len; 2969 2970 if (p == NULL) 2971 return -1; 2972 TRACE("adding string(s) from array\n"); 2973 while (*p) { 2974 len = strlenW (p); 2975 2976 TRACE("len=%d %s\n", len, debugstr_w(p)); 2977 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 2978 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p); 2979 infoPtr->nNumStrings++; 2980 2981 p += (len+1); 2982 } 2983 } 2984 2985 if (fFirstString) 2986 TOOLBAR_CalcToolbar(infoPtr); 2987 return nIndex; 2988 } 2989 2990 2991 static LRESULT 2992 TOOLBAR_AddStringA (TOOLBAR_INFO *infoPtr, HINSTANCE hInstance, LPARAM lParam) 2993 { 2994 BOOL fFirstString = (infoPtr->nNumStrings == 0); 2995 LPSTR p; 2996 INT nIndex; 2997 INT len; 2998 2999 TRACE("%p, %lx\n", hInstance, lParam); 3000 3001 if (IS_INTRESOURCE(lParam)) /* load from resources */ 3002 return TOOLBAR_AddStringW(infoPtr, hInstance, lParam); 3003 3004 p = (LPSTR)lParam; 3005 if (p == NULL) 3006 return -1; 3007 3008 TRACE("adding string(s) from array\n"); 3009 nIndex = infoPtr->nNumStrings; 3010 while (*p) { 3011 len = strlen (p); 3012 TRACE("len=%d \"%s\"\n", len, p); 3013 3014 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 3015 Str_SetPtrAtoW(&infoPtr->strings[infoPtr->nNumStrings], p); 3016 infoPtr->nNumStrings++; 3017 3018 p += (len+1); 3019 } 3020 3021 if (fFirstString) 3022 TOOLBAR_CalcToolbar(infoPtr); 3023 return nIndex; 3024 } 3025 3026 3027 static LRESULT 3028 TOOLBAR_AutoSize (TOOLBAR_INFO *infoPtr) 3029 { 3030 RECT parent_rect; 3031 HWND parent; 3032 INT x, y; 3033 INT cx, cy; 3034 3035 TRACE("auto sizing, style=%x!\n", infoPtr->dwStyle); 3036 3037 parent = GetParent (infoPtr->hwndSelf); 3038 3039 if (!parent || !infoPtr->bDoRedraw) 3040 return 0; 3041 3042 GetClientRect(parent, &parent_rect); 3043 3044 x = parent_rect.left; 3045 y = parent_rect.top; 3046 3047 TRACE("nRows: %d, infoPtr->nButtonHeight: %d\n", infoPtr->nRows, infoPtr->nButtonHeight); 3048 3049 cy = TOP_BORDER + infoPtr->nRows * infoPtr->nButtonHeight + BOTTOM_BORDER; 3050 cx = parent_rect.right - parent_rect.left; 3051 3052 if ((infoPtr->dwStyle & TBSTYLE_WRAPABLE) || (infoPtr->dwExStyle & TBSTYLE_EX_VERTICAL)) 3053 { 3054 TOOLBAR_LayoutToolbar(infoPtr); 3055 InvalidateRect( infoPtr->hwndSelf, NULL, TRUE ); 3056 } 3057 3058 if (!(infoPtr->dwStyle & CCS_NORESIZE)) 3059 { 3060 RECT window_rect; 3061 UINT uPosFlags = SWP_NOZORDER | SWP_NOACTIVATE; 3062 3063 if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) 3064 { 3065 GetWindowRect(infoPtr->hwndSelf, &window_rect); 3066 MapWindowPoints( 0, parent, (POINT *)&window_rect, 2 ); 3067 y = window_rect.top; 3068 } 3069 if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_BOTTOM) 3070 { 3071 GetWindowRect(infoPtr->hwndSelf, &window_rect); 3072 y = parent_rect.bottom - ( window_rect.bottom - window_rect.top); 3073 } 3074 3075 if (infoPtr->dwStyle & CCS_NOPARENTALIGN) 3076 uPosFlags |= SWP_NOMOVE; 3077 3078 if (!(infoPtr->dwStyle & CCS_NODIVIDER)) 3079 cy += GetSystemMetrics(SM_CYEDGE); 3080 3081 if (infoPtr->dwStyle & WS_BORDER) 3082 { 3083 cx += 2 * GetSystemMetrics(SM_CXBORDER); 3084 cy += 2 * GetSystemMetrics(SM_CYBORDER); 3085 } 3086 3087 SetWindowPos(infoPtr->hwndSelf, NULL, x, y, cx, cy, uPosFlags); 3088 } 3089 3090 return 0; 3091 } 3092 3093 3094 static inline LRESULT 3095 TOOLBAR_ButtonCount (const TOOLBAR_INFO *infoPtr) 3096 { 3097 return infoPtr->nNumButtons; 3098 } 3099 3100 3101 static inline LRESULT 3102 TOOLBAR_ButtonStructSize (TOOLBAR_INFO *infoPtr, DWORD Size) 3103 { 3104 infoPtr->dwStructSize = Size; 3105 3106 return 0; 3107 } 3108 3109 3110 static LRESULT 3111 TOOLBAR_ChangeBitmap (TOOLBAR_INFO *infoPtr, INT Id, INT Index) 3112 { 3113 TBUTTON_INFO *btnPtr; 3114 INT nIndex; 3115 3116 TRACE("button %d, iBitmap now %d\n", Id, Index); 3117 3118 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3119 if (nIndex == -1) 3120 return FALSE; 3121 3122 btnPtr = &infoPtr->buttons[nIndex]; 3123 btnPtr->iBitmap = Index; 3124 3125 /* we HAVE to erase the background, the new bitmap could be */ 3126 /* transparent */ 3127 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 3128 3129 return TRUE; 3130 } 3131 3132 3133 static LRESULT 3134 TOOLBAR_CheckButton (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 3135 { 3136 TBUTTON_INFO *btnPtr; 3137 INT nIndex; 3138 INT nOldIndex = -1; 3139 BOOL bChecked = FALSE; 3140 3141 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3142 3143 TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", infoPtr->hwndSelf, nIndex, lParam); 3144 3145 if (nIndex == -1) 3146 return FALSE; 3147 3148 btnPtr = &infoPtr->buttons[nIndex]; 3149 3150 bChecked = (btnPtr->fsState & TBSTATE_CHECKED) != 0; 3151 3152 if (LOWORD(lParam) == FALSE) 3153 btnPtr->fsState &= ~TBSTATE_CHECKED; 3154 else { 3155 if (btnPtr->fsStyle & BTNS_GROUP) { 3156 nOldIndex = 3157 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex); 3158 if (nOldIndex == nIndex) 3159 return 0; 3160 if (nOldIndex != -1) 3161 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; 3162 } 3163 btnPtr->fsState |= TBSTATE_CHECKED; 3164 } 3165 3166 if( bChecked != LOWORD(lParam) ) 3167 { 3168 if (nOldIndex != -1) 3169 InvalidateRect(infoPtr->hwndSelf, &infoPtr->buttons[nOldIndex].rect, TRUE); 3170 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 3171 } 3172 3173 /* FIXME: Send a WM_NOTIFY?? */ 3174 3175 return TRUE; 3176 } 3177 3178 3179 static LRESULT 3180 TOOLBAR_CommandToIndex (const TOOLBAR_INFO *infoPtr, INT Id) 3181 { 3182 return TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3183 } 3184 3185 3186 static LRESULT 3187 TOOLBAR_Customize (TOOLBAR_INFO *infoPtr) 3188 { 3189 CUSTDLG_INFO custInfo; 3190 LRESULT ret; 3191 NMHDR nmhdr; 3192 3193 custInfo.tbInfo = infoPtr; 3194 custInfo.tbHwnd = infoPtr->hwndSelf; 3195 3196 /* send TBN_BEGINADJUST notification */ 3197 TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_BEGINADJUST); 3198 3199 ret = DialogBoxParamW (COMCTL32_hModule, MAKEINTRESOURCEW(IDD_TBCUSTOMIZE), 3200 infoPtr->hwndSelf, TOOLBAR_CustomizeDialogProc, (LPARAM)&custInfo); 3201 3202 /* send TBN_ENDADJUST notification */ 3203 TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_ENDADJUST); 3204 3205 return ret; 3206 } 3207 3208 3209 static LRESULT 3210 TOOLBAR_DeleteButton (TOOLBAR_INFO *infoPtr, INT nIndex) 3211 { 3212 NMTOOLBARW nmtb; 3213 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nIndex]; 3214 3215 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 3216 return FALSE; 3217 3218 memset(&nmtb, 0, sizeof(nmtb)); 3219 nmtb.iItem = btnPtr->idCommand; 3220 nmtb.tbButton.iBitmap = btnPtr->iBitmap; 3221 nmtb.tbButton.idCommand = btnPtr->idCommand; 3222 nmtb.tbButton.fsState = btnPtr->fsState; 3223 nmtb.tbButton.fsStyle = btnPtr->fsStyle; 3224 nmtb.tbButton.dwData = btnPtr->dwData; 3225 nmtb.tbButton.iString = btnPtr->iString; 3226 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_DELETINGBUTTON); 3227 3228 TOOLBAR_TooltipDelTool(infoPtr, &infoPtr->buttons[nIndex]); 3229 3230 if (infoPtr->nNumButtons == 1) { 3231 TRACE(" simple delete!\n"); 3232 if (TOOLBAR_ButtonHasString(infoPtr->buttons)) 3233 Free((LPWSTR)infoPtr->buttons[0].iString); 3234 Free (infoPtr->buttons); 3235 infoPtr->buttons = NULL; 3236 infoPtr->nNumButtons = 0; 3237 } 3238 else { 3239 TBUTTON_INFO *oldButtons = infoPtr->buttons; 3240 TRACE("complex delete! [nIndex=%d]\n", nIndex); 3241 3242 infoPtr->nNumButtons--; 3243 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); 3244 if (nIndex > 0) { 3245 memcpy (&infoPtr->buttons[0], &oldButtons[0], 3246 nIndex * sizeof(TBUTTON_INFO)); 3247 } 3248 3249 if (nIndex < infoPtr->nNumButtons) { 3250 memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1], 3251 (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO)); 3252 } 3253 3254 if (TOOLBAR_ButtonHasString(&oldButtons[nIndex])) 3255 Free((LPWSTR)oldButtons[nIndex].iString); 3256 Free (oldButtons); 3257 } 3258 3259 TOOLBAR_LayoutToolbar(infoPtr); 3260 3261 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 3262 3263 return TRUE; 3264 } 3265 3266 3267 static LRESULT 3268 TOOLBAR_EnableButton (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 3269 { 3270 TBUTTON_INFO *btnPtr; 3271 INT nIndex; 3272 DWORD bState; 3273 3274 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3275 3276 TRACE("hwnd=%p, btn id=%d, lParam=0x%08lx\n", infoPtr->hwndSelf, Id, lParam); 3277 3278 if (nIndex == -1) 3279 return FALSE; 3280 3281 btnPtr = &infoPtr->buttons[nIndex]; 3282 3283 bState = btnPtr->fsState & TBSTATE_ENABLED; 3284 3285 /* update the toolbar button state */ 3286 if(LOWORD(lParam) == FALSE) { 3287 btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED); 3288 } else { 3289 btnPtr->fsState |= TBSTATE_ENABLED; 3290 } 3291 3292 /* redraw the button only if the state of the button changed */ 3293 if(bState != (btnPtr->fsState & TBSTATE_ENABLED)) 3294 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 3295 3296 return TRUE; 3297 } 3298 3299 3300 static inline LRESULT 3301 TOOLBAR_GetAnchorHighlight (const TOOLBAR_INFO *infoPtr) 3302 { 3303 return infoPtr->bAnchor; 3304 } 3305 3306 3307 static LRESULT 3308 TOOLBAR_GetBitmap (const TOOLBAR_INFO *infoPtr, INT Id) 3309 { 3310 INT nIndex; 3311 3312 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3313 if (nIndex == -1) 3314 return -1; 3315 3316 return infoPtr->buttons[nIndex].iBitmap; 3317 } 3318 3319 3320 static inline LRESULT 3321 TOOLBAR_GetBitmapFlags (void) 3322 { 3323 return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0; 3324 } 3325 3326 3327 static LRESULT 3328 TOOLBAR_GetButton (const TOOLBAR_INFO *infoPtr, INT nIndex, TBBUTTON *lpTbb) 3329 { 3330 TBUTTON_INFO *btnPtr; 3331 3332 if (lpTbb == NULL) 3333 return FALSE; 3334 3335 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 3336 return FALSE; 3337 3338 btnPtr = &infoPtr->buttons[nIndex]; 3339 lpTbb->iBitmap = btnPtr->iBitmap; 3340 lpTbb->idCommand = btnPtr->idCommand; 3341 lpTbb->fsState = btnPtr->fsState; 3342 lpTbb->fsStyle = btnPtr->fsStyle; 3343 lpTbb->bReserved[0] = 0; 3344 lpTbb->bReserved[1] = 0; 3345 lpTbb->dwData = btnPtr->dwData; 3346 lpTbb->iString = btnPtr->iString; 3347 3348 return TRUE; 3349 } 3350 3351 3352 static LRESULT 3353 TOOLBAR_GetButtonInfoT(const TOOLBAR_INFO *infoPtr, INT Id, LPTBBUTTONINFOW lpTbInfo, BOOL bUnicode) 3354 { 3355 /* TBBUTTONINFOW and TBBUTTONINFOA have the same layout*/ 3356 TBUTTON_INFO *btnPtr; 3357 INT nIndex; 3358 3359 if (lpTbInfo == NULL) 3360 return -1; 3361 3362 /* MSDN documents an iImageLabel field added in Vista but it is not present in 3363 * the headers and tests shows that even with comctl 6 Vista accepts only the 3364 * original TBBUTTONINFO size 3365 */ 3366 if (lpTbInfo->cbSize != sizeof(TBBUTTONINFOW)) 3367 { 3368 WARN("Invalid button size\n"); 3369 return -1; 3370 } 3371 3372 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, lpTbInfo->dwMask & TBIF_BYINDEX); 3373 if (nIndex == -1) 3374 return -1; 3375 3376 if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1; 3377 3378 if (lpTbInfo->dwMask & TBIF_COMMAND) 3379 lpTbInfo->idCommand = btnPtr->idCommand; 3380 if (lpTbInfo->dwMask & TBIF_IMAGE) 3381 lpTbInfo->iImage = btnPtr->iBitmap; 3382 if (lpTbInfo->dwMask & TBIF_LPARAM) 3383 lpTbInfo->lParam = btnPtr->dwData; 3384 if (lpTbInfo->dwMask & TBIF_SIZE) 3385 /* tests show that for separators TBIF_SIZE returns not calculated width, 3386 but cx property, that differs from 0 only if application have 3387 specifically set it */ 3388 lpTbInfo->cx = (btnPtr->fsStyle & BTNS_SEP) 3389 ? btnPtr->cx : (WORD)(btnPtr->rect.right - btnPtr->rect.left); 3390 if (lpTbInfo->dwMask & TBIF_STATE) 3391 lpTbInfo->fsState = btnPtr->fsState; 3392 if (lpTbInfo->dwMask & TBIF_STYLE) 3393 lpTbInfo->fsStyle = btnPtr->fsStyle; 3394 if (lpTbInfo->dwMask & TBIF_TEXT) { 3395 /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we 3396 can't use TOOLBAR_GetText here */ 3397 if (!IS_INTRESOURCE(btnPtr->iString) && (btnPtr->iString != -1)) { 3398 LPWSTR lpText = (LPWSTR)btnPtr->iString; 3399 if (bUnicode) 3400 Str_GetPtrW(lpText, lpTbInfo->pszText, lpTbInfo->cchText); 3401 else 3402 Str_GetPtrWtoA(lpText, (LPSTR)lpTbInfo->pszText, lpTbInfo->cchText); 3403 } else 3404 lpTbInfo->pszText[0] = '\0'; 3405 } 3406 return nIndex; 3407 } 3408 3409 3410 static inline LRESULT 3411 TOOLBAR_GetButtonSize (const TOOLBAR_INFO *infoPtr) 3412 { 3413 return MAKELONG((WORD)infoPtr->nButtonWidth, 3414 (WORD)infoPtr->nButtonHeight); 3415 } 3416 3417 3418 static LRESULT 3419 TOOLBAR_GetButtonText (const TOOLBAR_INFO *infoPtr, INT Id, LPWSTR lpStr, BOOL isW) 3420 { 3421 INT nIndex; 3422 LPWSTR lpText; 3423 LRESULT ret = 0; 3424 3425 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3426 if (nIndex == -1) 3427 return -1; 3428 3429 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); 3430 3431 if (isW) 3432 { 3433 if (lpText) 3434 { 3435 ret = strlenW (lpText); 3436 if (lpStr) strcpyW (lpStr, lpText); 3437 } 3438 } 3439 else 3440 ret = WideCharToMultiByte( CP_ACP, 0, lpText, -1, 3441 (LPSTR)lpStr, lpStr ? 0x7fffffff : 0, NULL, NULL ) - 1; 3442 return ret; 3443 } 3444 3445 3446 static LRESULT 3447 TOOLBAR_GetDisabledImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 3448 { 3449 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 3450 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 3451 return (LRESULT)GETDISIMAGELIST(infoPtr, wParam); 3452 } 3453 3454 3455 static inline LRESULT 3456 TOOLBAR_GetExtendedStyle (const TOOLBAR_INFO *infoPtr) 3457 { 3458 TRACE("\n"); 3459 3460 return infoPtr->dwExStyle; 3461 } 3462 3463 3464 static LRESULT 3465 TOOLBAR_GetHotImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 3466 { 3467 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 3468 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 3469 return (LRESULT)GETHOTIMAGELIST(infoPtr, wParam); 3470 } 3471 3472 3473 static LRESULT 3474 TOOLBAR_GetHotItem (const TOOLBAR_INFO *infoPtr) 3475 { 3476 if (!((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))) 3477 return -1; 3478 3479 if (infoPtr->nHotItem < 0) 3480 return -1; 3481 3482 return (LRESULT)infoPtr->nHotItem; 3483 } 3484 3485 3486 static LRESULT 3487 TOOLBAR_GetDefImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 3488 { 3489 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 3490 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 3491 return (LRESULT) GETDEFIMAGELIST(infoPtr, wParam); 3492 } 3493 3494 3495 static LRESULT 3496 TOOLBAR_GetInsertMark (const TOOLBAR_INFO *infoPtr, TBINSERTMARK *lptbim) 3497 { 3498 TRACE("hwnd = %p, lptbim = %p\n", infoPtr->hwndSelf, lptbim); 3499 3500 *lptbim = infoPtr->tbim; 3501 3502 return 0; 3503 } 3504 3505 3506 static inline LRESULT 3507 TOOLBAR_GetInsertMarkColor (const TOOLBAR_INFO *infoPtr) 3508 { 3509 TRACE("hwnd = %p\n", infoPtr->hwndSelf); 3510 3511 return (LRESULT)infoPtr->clrInsertMark; 3512 } 3513 3514 3515 static LRESULT 3516 TOOLBAR_GetItemRect (const TOOLBAR_INFO *infoPtr, INT nIndex, LPRECT lpRect) 3517 { 3518 TBUTTON_INFO *btnPtr; 3519 3520 btnPtr = &infoPtr->buttons[nIndex]; 3521 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 3522 return FALSE; 3523 3524 if (lpRect == NULL) 3525 return FALSE; 3526 if (btnPtr->fsState & TBSTATE_HIDDEN) 3527 return FALSE; 3528 3529 lpRect->left = btnPtr->rect.left; 3530 lpRect->right = btnPtr->rect.right; 3531 lpRect->bottom = btnPtr->rect.bottom; 3532 lpRect->top = btnPtr->rect.top; 3533 3534 return TRUE; 3535 } 3536 3537 3538 static LRESULT 3539 TOOLBAR_GetMaxSize (const TOOLBAR_INFO *infoPtr, LPSIZE lpSize) 3540 { 3541 if (lpSize == NULL) 3542 return FALSE; 3543 3544 lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 3545 lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 3546 3547 TRACE("maximum size %d x %d\n", 3548 infoPtr->rcBound.right - infoPtr->rcBound.left, 3549 infoPtr->rcBound.bottom - infoPtr->rcBound.top); 3550 3551 return TRUE; 3552 } 3553 3554 3555 static LRESULT 3556 TOOLBAR_GetMetrics (const TOOLBAR_INFO *infoPtr, TBMETRICS *pMetrics) 3557 { 3558 if (pMetrics == NULL) 3559 return FALSE; 3560 3561 /* TODO: check if cbSize is a valid value */ 3562 3563 if (pMetrics->dwMask & TBMF_PAD) 3564 { 3565 pMetrics->cxPad = infoPtr->szPadding.cx; 3566 pMetrics->cyPad = infoPtr->szPadding.cy; 3567 } 3568 3569 if (pMetrics->dwMask & TBMF_BARPAD) 3570 { 3571 pMetrics->cxBarPad = infoPtr->szBarPadding.cx; 3572 pMetrics->cyBarPad = infoPtr->szBarPadding.cy; 3573 } 3574 3575 if (pMetrics->dwMask & TBMF_BUTTONSPACING) 3576 { 3577 pMetrics->cxButtonSpacing = infoPtr->szSpacing.cx; 3578 pMetrics->cyButtonSpacing = infoPtr->szSpacing.cy; 3579 } 3580 3581 return TRUE; 3582 } 3583 3584 3585 /* << TOOLBAR_GetObject >> */ 3586 3587 3588 static inline LRESULT 3589 TOOLBAR_GetPadding (const TOOLBAR_INFO *infoPtr) 3590 { 3591 return MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); 3592 } 3593 3594 3595 static LRESULT 3596 TOOLBAR_GetRect (const TOOLBAR_INFO *infoPtr, INT Id, LPRECT lpRect) 3597 { 3598 TBUTTON_INFO *btnPtr; 3599 INT nIndex; 3600 3601 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3602 btnPtr = &infoPtr->buttons[nIndex]; 3603 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 3604 return FALSE; 3605 3606 if (lpRect == NULL) 3607 return FALSE; 3608 3609 lpRect->left = btnPtr->rect.left; 3610 lpRect->right = btnPtr->rect.right; 3611 lpRect->bottom = btnPtr->rect.bottom; 3612 lpRect->top = btnPtr->rect.top; 3613 3614 return TRUE; 3615 } 3616 3617 3618 static inline LRESULT 3619 TOOLBAR_GetRows (const TOOLBAR_INFO *infoPtr) 3620 { 3621 return infoPtr->nRows; 3622 } 3623 3624 3625 static LRESULT 3626 TOOLBAR_GetState (const TOOLBAR_INFO *infoPtr, INT Id) 3627 { 3628 INT nIndex; 3629 3630 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3631 if (nIndex == -1) 3632 return -1; 3633 3634 return infoPtr->buttons[nIndex].fsState; 3635 } 3636 3637 3638 static inline LRESULT 3639 TOOLBAR_GetStyle (const TOOLBAR_INFO *infoPtr) 3640 { 3641 return infoPtr->dwStyle; 3642 } 3643 3644 3645 static inline LRESULT 3646 TOOLBAR_GetTextRows (const TOOLBAR_INFO *infoPtr) 3647 { 3648 return infoPtr->nMaxTextRows; 3649 } 3650 3651 3652 static LRESULT 3653 TOOLBAR_GetToolTips (TOOLBAR_INFO *infoPtr) 3654 { 3655 if ((infoPtr->dwStyle & TBSTYLE_TOOLTIPS) && (infoPtr->hwndToolTip == NULL)) 3656 TOOLBAR_TooltipCreateControl(infoPtr); 3657 return (LRESULT)infoPtr->hwndToolTip; 3658 } 3659 3660 3661 static LRESULT 3662 TOOLBAR_GetUnicodeFormat (const TOOLBAR_INFO *infoPtr) 3663 { 3664 TRACE("%s hwnd=%p\n", 3665 infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); 3666 3667 return infoPtr->bUnicode; 3668 } 3669 3670 3671 static inline LRESULT 3672 TOOLBAR_GetVersion (const TOOLBAR_INFO *infoPtr) 3673 { 3674 return infoPtr->iVersion; 3675 } 3676 3677 3678 static LRESULT 3679 TOOLBAR_HideButton (TOOLBAR_INFO *infoPtr, INT Id, BOOL fHide) 3680 { 3681 TBUTTON_INFO *btnPtr; 3682 BYTE oldState; 3683 INT nIndex; 3684 3685 TRACE("\n"); 3686 3687 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3688 if (nIndex == -1) 3689 return FALSE; 3690 3691 btnPtr = &infoPtr->buttons[nIndex]; 3692 oldState = btnPtr->fsState; 3693 3694 if (fHide) 3695 btnPtr->fsState |= TBSTATE_HIDDEN; 3696 else 3697 btnPtr->fsState &= ~TBSTATE_HIDDEN; 3698 3699 if (oldState != btnPtr->fsState) { 3700 TOOLBAR_LayoutToolbar (infoPtr); 3701 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 3702 } 3703 3704 return TRUE; 3705 } 3706 3707 3708 static inline LRESULT 3709 TOOLBAR_HitTest (const TOOLBAR_INFO *infoPtr, const POINT* lpPt) 3710 { 3711 return TOOLBAR_InternalHitTest (infoPtr, lpPt, NULL); 3712 } 3713 3714 3715 static LRESULT 3716 TOOLBAR_Indeterminate (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fIndeterminate) 3717 { 3718 TBUTTON_INFO *btnPtr; 3719 INT nIndex; 3720 DWORD oldState; 3721 3722 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3723 if (nIndex == -1) 3724 return FALSE; 3725 3726 btnPtr = &infoPtr->buttons[nIndex]; 3727 oldState = btnPtr->fsState; 3728 3729 if (fIndeterminate) 3730 btnPtr->fsState |= TBSTATE_INDETERMINATE; 3731 else 3732 btnPtr->fsState &= ~TBSTATE_INDETERMINATE; 3733 3734 if(oldState != btnPtr->fsState) 3735 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 3736 3737 return TRUE; 3738 } 3739 3740 3741 static LRESULT 3742 TOOLBAR_InsertButtonT(TOOLBAR_INFO *infoPtr, INT nIndex, const TBBUTTON *lpTbb, BOOL fUnicode) 3743 { 3744 if (lpTbb == NULL) 3745 return FALSE; 3746 3747 if (nIndex == -1) { 3748 /* EPP: this seems to be an undocumented call (from my IE4) 3749 * I assume in that case that: 3750 * - index of insertion is at the end of existing buttons 3751 * I only see this happen with nIndex == -1, but it could have a special 3752 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). 3753 */ 3754 nIndex = infoPtr->nNumButtons; 3755 3756 } else if (nIndex < 0) 3757 return FALSE; 3758 3759 TRACE("inserting button index=%d\n", nIndex); 3760 if (nIndex > infoPtr->nNumButtons) { 3761 nIndex = infoPtr->nNumButtons; 3762 TRACE("adjust index=%d\n", nIndex); 3763 } 3764 3765 return TOOLBAR_InternalInsertButtonsT(infoPtr, nIndex, 1, lpTbb, fUnicode); 3766 } 3767 3768 /* << TOOLBAR_InsertMarkHitTest >> */ 3769 3770 3771 static LRESULT 3772 TOOLBAR_IsButtonChecked (const TOOLBAR_INFO *infoPtr, INT Id) 3773 { 3774 INT nIndex; 3775 3776 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3777 if (nIndex == -1) 3778 return -1; 3779 3780 return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED); 3781 } 3782 3783 3784 static LRESULT 3785 TOOLBAR_IsButtonEnabled (const TOOLBAR_INFO *infoPtr, INT Id) 3786 { 3787 INT nIndex; 3788 3789 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3790 if (nIndex == -1) 3791 return -1; 3792 3793 return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED); 3794 } 3795 3796 3797 static LRESULT 3798 TOOLBAR_IsButtonHidden (const TOOLBAR_INFO *infoPtr, INT Id) 3799 { 3800 INT nIndex; 3801 3802 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3803 if (nIndex == -1) 3804 return -1; 3805 3806 return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN); 3807 } 3808 3809 3810 static LRESULT 3811 TOOLBAR_IsButtonHighlighted (const TOOLBAR_INFO *infoPtr, INT Id) 3812 { 3813 INT nIndex; 3814 3815 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3816 if (nIndex == -1) 3817 return -1; 3818 3819 return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED); 3820 } 3821 3822 3823 static LRESULT 3824 TOOLBAR_IsButtonIndeterminate (const TOOLBAR_INFO *infoPtr, INT Id) 3825 { 3826 INT nIndex; 3827 3828 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3829 if (nIndex == -1) 3830 return -1; 3831 3832 return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE); 3833 } 3834 3835 3836 static LRESULT 3837 TOOLBAR_IsButtonPressed (const TOOLBAR_INFO *infoPtr, INT Id) 3838 { 3839 INT nIndex; 3840 3841 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3842 if (nIndex == -1) 3843 return -1; 3844 3845 return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED); 3846 } 3847 3848 3849 static LRESULT 3850 TOOLBAR_LoadImages (TOOLBAR_INFO *infoPtr, WPARAM wParam, HINSTANCE hInstance) 3851 { 3852 TBADDBITMAP tbab; 3853 tbab.hInst = hInstance; 3854 tbab.nID = wParam; 3855 3856 TRACE("hwnd = %p, hInst = %p, nID = %lu\n", infoPtr->hwndSelf, tbab.hInst, tbab.nID); 3857 3858 return TOOLBAR_AddBitmap(infoPtr, 0, &tbab); 3859 } 3860 3861 3862 static LRESULT 3863 TOOLBAR_MapAccelerator (const TOOLBAR_INFO *infoPtr, WCHAR wAccel, UINT *pIDButton) 3864 { 3865 WCHAR wszAccel[] = {'&',wAccel,0}; 3866 int i; 3867 3868 TRACE("hwnd = %p, wAccel = %x(%s), pIDButton = %p\n", 3869 infoPtr->hwndSelf, wAccel, debugstr_wn(&wAccel,1), pIDButton); 3870 3871 for (i = 0; i < infoPtr->nNumButtons; i++) 3872 { 3873 TBUTTON_INFO *btnPtr = infoPtr->buttons+i; 3874 if (!(btnPtr->fsStyle & BTNS_NOPREFIX) && 3875 !(btnPtr->fsState & TBSTATE_HIDDEN)) 3876 { 3877 int iLen = strlenW(wszAccel); 3878 LPCWSTR lpszStr = TOOLBAR_GetText(infoPtr, btnPtr); 3879 3880 if (!lpszStr) 3881 continue; 3882 3883 while (*lpszStr) 3884 { 3885 if ((lpszStr[0] == '&') && (lpszStr[1] == '&')) 3886 { 3887 lpszStr += 2; 3888 continue; 3889 } 3890 if (!strncmpiW(lpszStr, wszAccel, iLen)) 3891 { 3892 *pIDButton = btnPtr->idCommand; 3893 return TRUE; 3894 } 3895 lpszStr++; 3896 } 3897 } 3898 } 3899 return FALSE; 3900 } 3901 3902 3903 static LRESULT 3904 TOOLBAR_MarkButton (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fMark) 3905 { 3906 INT nIndex; 3907 DWORD oldState; 3908 TBUTTON_INFO *btnPtr; 3909 3910 TRACE("hwnd = %p, Id = %d, fMark = 0%d\n", infoPtr->hwndSelf, Id, fMark); 3911 3912 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 3913 if (nIndex == -1) 3914 return FALSE; 3915 3916 btnPtr = &infoPtr->buttons[nIndex]; 3917 oldState = btnPtr->fsState; 3918 3919 if (fMark) 3920 btnPtr->fsState |= TBSTATE_MARKED; 3921 else 3922 btnPtr->fsState &= ~TBSTATE_MARKED; 3923 3924 if(oldState != btnPtr->fsState) 3925 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 3926 3927 return TRUE; 3928 } 3929 3930 3931 /* fixes up an index of a button affected by a move */ 3932 static inline void TOOLBAR_MoveFixupIndex(INT* pIndex, INT nIndex, INT nMoveIndex, BOOL bMoveUp) 3933 { 3934 if (bMoveUp) 3935 { 3936 if (*pIndex > nIndex && *pIndex <= nMoveIndex) 3937 (*pIndex)--; 3938 else if (*pIndex == nIndex) 3939 *pIndex = nMoveIndex; 3940 } 3941 else 3942 { 3943 if (*pIndex >= nMoveIndex && *pIndex < nIndex) 3944 (*pIndex)++; 3945 else if (*pIndex == nIndex) 3946 *pIndex = nMoveIndex; 3947 } 3948 } 3949 3950 3951 static LRESULT 3952 TOOLBAR_MoveButton (TOOLBAR_INFO *infoPtr, INT Id, INT nMoveIndex) 3953 { 3954 INT nIndex; 3955 INT nCount; 3956 TBUTTON_INFO button; 3957 3958 TRACE("hwnd=%p, Id=%d, nMoveIndex=%d\n", infoPtr->hwndSelf, Id, nMoveIndex); 3959 3960 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, TRUE); 3961 if ((nIndex == -1) || (nMoveIndex < 0)) 3962 return FALSE; 3963 3964 if (nMoveIndex > infoPtr->nNumButtons - 1) 3965 nMoveIndex = infoPtr->nNumButtons - 1; 3966 3967 button = infoPtr->buttons[nIndex]; 3968 3969 /* move button right */ 3970 if (nIndex < nMoveIndex) 3971 { 3972 nCount = nMoveIndex - nIndex; 3973 memmove(&infoPtr->buttons[nIndex], &infoPtr->buttons[nIndex+1], nCount*sizeof(TBUTTON_INFO)); 3974 infoPtr->buttons[nMoveIndex] = button; 3975 3976 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, TRUE); 3977 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, TRUE); 3978 TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, TRUE); 3979 TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, TRUE); 3980 } 3981 else if (nIndex > nMoveIndex) /* move button left */ 3982 { 3983 nCount = nIndex - nMoveIndex; 3984 memmove(&infoPtr->buttons[nMoveIndex+1], &infoPtr->buttons[nMoveIndex], nCount*sizeof(TBUTTON_INFO)); 3985 infoPtr->buttons[nMoveIndex] = button; 3986 3987 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, FALSE); 3988 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, FALSE); 3989 TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, FALSE); 3990 TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, FALSE); 3991 } 3992 3993 TOOLBAR_LayoutToolbar(infoPtr); 3994 TOOLBAR_AutoSize(infoPtr); 3995 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 3996 3997 return TRUE; 3998 } 3999 4000 4001 static LRESULT 4002 TOOLBAR_PressButton (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fPress) 4003 { 4004 TBUTTON_INFO *btnPtr; 4005 INT nIndex; 4006 DWORD oldState; 4007 4008 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 4009 if (nIndex == -1) 4010 return FALSE; 4011 4012 btnPtr = &infoPtr->buttons[nIndex]; 4013 oldState = btnPtr->fsState; 4014 4015 if (fPress) 4016 btnPtr->fsState |= TBSTATE_PRESSED; 4017 else 4018 btnPtr->fsState &= ~TBSTATE_PRESSED; 4019 4020 if(oldState != btnPtr->fsState) 4021 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 4022 4023 return TRUE; 4024 } 4025 4026 /* FIXME: there might still be some confusion her between number of buttons 4027 * and number of bitmaps */ 4028 static LRESULT 4029 TOOLBAR_ReplaceBitmap (TOOLBAR_INFO *infoPtr, const TBREPLACEBITMAP *lpReplace) 4030 { 4031 HBITMAP hBitmap; 4032 int i = 0, nOldButtons = 0, pos = 0; 4033 int nOldBitmaps, nNewBitmaps = 0; 4034 HIMAGELIST himlDef = 0; 4035 4036 TRACE("hInstOld %p nIDOld %lx hInstNew %p nIDNew %lx nButtons %x\n", 4037 lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew, 4038 lpReplace->nButtons); 4039 4040 if (lpReplace->hInstOld == HINST_COMMCTRL) 4041 { 4042 FIXME("changing standard bitmaps not implemented\n"); 4043 return FALSE; 4044 } 4045 else if (lpReplace->hInstOld != 0 && lpReplace->hInstOld != lpReplace->hInstNew) 4046 FIXME("resources not in the current module not implemented\n"); 4047 4048 TRACE("To be replaced hInstOld %p nIDOld %lx\n", lpReplace->hInstOld, lpReplace->nIDOld); 4049 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) { 4050 TBITMAP_INFO *tbi = &infoPtr->bitmaps[i]; 4051 TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); 4052 if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld) 4053 { 4054 TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID); 4055 nOldButtons = tbi->nButtons; 4056 tbi->nButtons = lpReplace->nButtons; 4057 tbi->hInst = lpReplace->hInstNew; 4058 tbi->nID = lpReplace->nIDNew; 4059 TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); 4060 break; 4061 } 4062 pos += tbi->nButtons; 4063 } 4064 4065 if (nOldButtons == 0) 4066 { 4067 WARN("No hinst/bitmap found! hInst %p nID %lx\n", lpReplace->hInstOld, lpReplace->nIDOld); 4068 return FALSE; 4069 } 4070 4071 /* copy the bitmap before adding it as ImageList_AddMasked modifies the 4072 * bitmap 4073 */ 4074 if (lpReplace->hInstNew) 4075 hBitmap = LoadBitmapW(lpReplace->hInstNew,(LPWSTR)lpReplace->nIDNew); 4076 else 4077 hBitmap = CopyImage((HBITMAP)lpReplace->nIDNew, IMAGE_BITMAP, 0, 0, 0); 4078 4079 himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */ 4080 nOldBitmaps = ImageList_GetImageCount(himlDef); 4081 4082 /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */ 4083 4084 for (i = pos + nOldBitmaps - 1; i >= pos; i--) 4085 ImageList_Remove(himlDef, i); 4086 4087 if (hBitmap) 4088 { 4089 ImageList_AddMasked (himlDef, hBitmap, comctl32_color.clrBtnFace); 4090 nNewBitmaps = ImageList_GetImageCount(himlDef); 4091 DeleteObject(hBitmap); 4092 } 4093 4094 infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps; 4095 4096 TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n", 4097 pos, nOldBitmaps, nNewBitmaps); 4098 4099 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4100 return TRUE; 4101 } 4102 4103 4104 /* helper for TOOLBAR_SaveRestoreW */ 4105 static BOOL 4106 TOOLBAR_Save(const TBSAVEPARAMSW *lpSave) 4107 { 4108 FIXME("save to %s %s\n", debugstr_w(lpSave->pszSubKey), 4109 debugstr_w(lpSave->pszValueName)); 4110 4111 return FALSE; 4112 } 4113 4114 4115 /* helper for TOOLBAR_Restore */ 4116 static void 4117 TOOLBAR_DeleteAllButtons(TOOLBAR_INFO *infoPtr) 4118 { 4119 INT i; 4120 4121 for (i = 0; i < infoPtr->nNumButtons; i++) 4122 { 4123 TOOLBAR_TooltipDelTool(infoPtr, &infoPtr->buttons[i]); 4124 } 4125 4126 Free(infoPtr->buttons); 4127 infoPtr->buttons = NULL; 4128 infoPtr->nNumButtons = 0; 4129 } 4130 4131 4132 /* helper for TOOLBAR_SaveRestoreW */ 4133 static BOOL 4134 TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, const TBSAVEPARAMSW *lpSave) 4135 { 4136 LONG res; 4137 HKEY hkey = NULL; 4138 BOOL ret = FALSE; 4139 DWORD dwType; 4140 DWORD dwSize = 0; 4141 NMTBRESTORE nmtbr; 4142 4143 /* restore toolbar information */ 4144 TRACE("restore from %s %s\n", debugstr_w(lpSave->pszSubKey), 4145 debugstr_w(lpSave->pszValueName)); 4146 4147 memset(&nmtbr, 0, sizeof(nmtbr)); 4148 4149 res = RegOpenKeyExW(lpSave->hkr, lpSave->pszSubKey, 0, 4150 KEY_QUERY_VALUE, &hkey); 4151 if (!res) 4152 res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, 4153 NULL, &dwSize); 4154 if (!res && dwType != REG_BINARY) 4155 res = ERROR_FILE_NOT_FOUND; 4156 if (!res) 4157 { 4158 nmtbr.pData = Alloc(dwSize); 4159 nmtbr.cbData = dwSize; 4160 if (!nmtbr.pData) res = ERROR_OUTOFMEMORY; 4161 } 4162 if (!res) 4163 res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, 4164 (LPBYTE)nmtbr.pData, &dwSize); 4165 if (!res) 4166 { 4167 nmtbr.pCurrent = nmtbr.pData; 4168 nmtbr.iItem = -1; 4169 nmtbr.cbBytesPerRecord = sizeof(DWORD); 4170 nmtbr.cButtons = nmtbr.cbData / nmtbr.cbBytesPerRecord; 4171 4172 if (!TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE)) 4173 { 4174 INT i; 4175 4176 /* remove all existing buttons as this function is designed to 4177 * restore the toolbar to a previously saved state */ 4178 TOOLBAR_DeleteAllButtons(infoPtr); 4179 4180 for (i = 0; i < nmtbr.cButtons; i++) 4181 { 4182 nmtbr.iItem = i; 4183 nmtbr.tbButton.iBitmap = -1; 4184 nmtbr.tbButton.fsState = 0; 4185 nmtbr.tbButton.fsStyle = 0; 4186 nmtbr.tbButton.idCommand = 0; 4187 if (*nmtbr.pCurrent == (DWORD)-1) 4188 { 4189 /* separator */ 4190 nmtbr.tbButton.fsStyle = TBSTYLE_SEP; 4191 /* when inserting separators, iBitmap controls its size. 4192 0 sets default size (width) */ 4193 nmtbr.tbButton.iBitmap = 0; 4194 } 4195 else if (*nmtbr.pCurrent == (DWORD)-2) 4196 /* hidden button */ 4197 nmtbr.tbButton.fsState = TBSTATE_HIDDEN; 4198 else 4199 nmtbr.tbButton.idCommand = (int)*nmtbr.pCurrent; 4200 4201 nmtbr.pCurrent++; 4202 4203 TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE); 4204 4205 /* can't contain real string as we don't know whether 4206 * the client put an ANSI or Unicode string in there */ 4207 if (!IS_INTRESOURCE(nmtbr.tbButton.iString)) 4208 nmtbr.tbButton.iString = 0; 4209 4210 TOOLBAR_InsertButtonT(infoPtr, -1, &nmtbr.tbButton, TRUE); 4211 } 4212 4213 /* do legacy notifications */ 4214 if (infoPtr->iVersion < 5) 4215 { 4216 /* FIXME: send TBN_BEGINADJUST */ 4217 FIXME("send TBN_GETBUTTONINFO for each button\n"); 4218 /* FIXME: send TBN_ENDADJUST */ 4219 } 4220 4221 /* remove all uninitialised buttons 4222 * note: loop backwards to avoid having to fixup i on a 4223 * delete */ 4224 for (i = infoPtr->nNumButtons - 1; i >= 0; i--) 4225 if (infoPtr->buttons[i].iBitmap == -1) 4226 TOOLBAR_DeleteButton(infoPtr, i); 4227 4228 /* only indicate success if at least one button survived */ 4229 if (infoPtr->nNumButtons > 0) ret = TRUE; 4230 } 4231 } 4232 Free (nmtbr.pData); 4233 RegCloseKey(hkey); 4234 4235 return ret; 4236 } 4237 4238 4239 static LRESULT 4240 TOOLBAR_SaveRestoreW (TOOLBAR_INFO *infoPtr, WPARAM wParam, const TBSAVEPARAMSW *lpSave) 4241 { 4242 if (lpSave == NULL) return 0; 4243 4244 if (wParam) 4245 return TOOLBAR_Save(lpSave); 4246 else 4247 return TOOLBAR_Restore(infoPtr, lpSave); 4248 } 4249 4250 4251 static LRESULT 4252 TOOLBAR_SaveRestoreA (TOOLBAR_INFO *infoPtr, WPARAM wParam, const TBSAVEPARAMSA *lpSave) 4253 { 4254 LPWSTR pszValueName = 0, pszSubKey = 0; 4255 TBSAVEPARAMSW SaveW; 4256 LRESULT result = 0; 4257 int len; 4258 4259 if (lpSave == NULL) return 0; 4260 4261 len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, NULL, 0); 4262 pszSubKey = Alloc(len * sizeof(WCHAR)); 4263 if (pszSubKey) goto exit; 4264 MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, pszSubKey, len); 4265 4266 len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, NULL, 0); 4267 pszValueName = Alloc(len * sizeof(WCHAR)); 4268 if (!pszValueName) goto exit; 4269 MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, pszValueName, len); 4270 4271 SaveW.pszValueName = pszValueName; 4272 SaveW.pszSubKey = pszSubKey; 4273 SaveW.hkr = lpSave->hkr; 4274 result = TOOLBAR_SaveRestoreW(infoPtr, wParam, &SaveW); 4275 4276 exit: 4277 Free (pszValueName); 4278 Free (pszSubKey); 4279 4280 return result; 4281 } 4282 4283 4284 static LRESULT 4285 TOOLBAR_SetAnchorHighlight (TOOLBAR_INFO *infoPtr, BOOL bAnchor) 4286 { 4287 BOOL bOldAnchor = infoPtr->bAnchor; 4288 4289 TRACE("hwnd=%p, bAnchor = %s\n", infoPtr->hwndSelf, bAnchor ? "TRUE" : "FALSE"); 4290 4291 infoPtr->bAnchor = bAnchor; 4292 4293 /* Native does not remove the hot effect from an already hot button */ 4294 4295 return (LRESULT)bOldAnchor; 4296 } 4297 4298 4299 static LRESULT 4300 TOOLBAR_SetBitmapSize (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4301 { 4302 HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0); 4303 short width = (short)LOWORD(lParam); 4304 short height = (short)HIWORD(lParam); 4305 4306 TRACE("hwnd=%p, wParam=%ld, lParam=%ld\n", infoPtr->hwndSelf, wParam, lParam); 4307 4308 if (wParam != 0) 4309 FIXME("wParam is %ld. Perhaps image list index?\n", wParam); 4310 4311 /* 0 width or height is changed to 1 */ 4312 if (width == 0) 4313 width = 1; 4314 if (height == 0) 4315 height = 1; 4316 4317 if (infoPtr->nNumButtons > 0) 4318 TRACE("%d buttons, undoc change to bitmap size : %d-%d -> %d-%d\n", 4319 infoPtr->nNumButtons, 4320 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, width, height); 4321 4322 if (width < -1 || height < -1) 4323 { 4324 /* Windows destroys the imagelist and seems to actually use negative 4325 * values to compute button sizes */ 4326 FIXME("Negative bitmap sizes not supported (%d, %d)\n", width, height); 4327 return FALSE; 4328 } 4329 4330 /* width or height of -1 means no change */ 4331 if (width != -1) 4332 infoPtr->nBitmapWidth = width; 4333 if (height != -1) 4334 infoPtr->nBitmapHeight = height; 4335 4336 if ((himlDef == infoPtr->himlInt) && 4337 (ImageList_GetImageCount(infoPtr->himlInt) == 0)) 4338 { 4339 ImageList_SetIconSize(infoPtr->himlInt, infoPtr->nBitmapWidth, 4340 infoPtr->nBitmapHeight); 4341 } 4342 4343 TOOLBAR_CalcToolbar(infoPtr); 4344 InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); 4345 return TRUE; 4346 } 4347 4348 4349 static LRESULT 4350 TOOLBAR_SetButtonInfo (TOOLBAR_INFO *infoPtr, INT Id, 4351 const TBBUTTONINFOW *lptbbi, BOOL isW) 4352 { 4353 TBUTTON_INFO *btnPtr; 4354 INT nIndex; 4355 RECT oldBtnRect; 4356 4357 if (lptbbi == NULL) 4358 return FALSE; 4359 if (lptbbi->cbSize < sizeof(TBBUTTONINFOW)) 4360 return FALSE; 4361 4362 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, lptbbi->dwMask & TBIF_BYINDEX); 4363 if (nIndex == -1) 4364 return FALSE; 4365 4366 btnPtr = &infoPtr->buttons[nIndex]; 4367 if (lptbbi->dwMask & TBIF_COMMAND) 4368 btnPtr->idCommand = lptbbi->idCommand; 4369 if (lptbbi->dwMask & TBIF_IMAGE) 4370 btnPtr->iBitmap = lptbbi->iImage; 4371 if (lptbbi->dwMask & TBIF_LPARAM) 4372 btnPtr->dwData = lptbbi->lParam; 4373 if (lptbbi->dwMask & TBIF_SIZE) 4374 btnPtr->cx = lptbbi->cx; 4375 if (lptbbi->dwMask & TBIF_STATE) 4376 btnPtr->fsState = lptbbi->fsState; 4377 if (lptbbi->dwMask & TBIF_STYLE) 4378 btnPtr->fsStyle = lptbbi->fsStyle; 4379 4380 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT_PTR)lptbbi->pszText != -1)) { 4381 /* iString is index, zero it to make Str_SetPtr succeed */ 4382 if (!TOOLBAR_ButtonHasString(btnPtr)) btnPtr->iString = 0; 4383 4384 if (isW) 4385 Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); 4386 else 4387 Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, (LPSTR)lptbbi->pszText); 4388 } 4389 4390 /* save the button rect to see if we need to redraw the whole toolbar */ 4391 oldBtnRect = btnPtr->rect; 4392 TOOLBAR_LayoutToolbar(infoPtr); 4393 4394 if (!EqualRect(&oldBtnRect, &btnPtr->rect)) 4395 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4396 else 4397 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 4398 4399 return TRUE; 4400 } 4401 4402 4403 static LRESULT 4404 TOOLBAR_SetButtonSize (TOOLBAR_INFO *infoPtr, LPARAM lParam) 4405 { 4406 INT cx = (short)LOWORD(lParam), cy = (short)HIWORD(lParam); 4407 4408 if ((cx < 0) || (cy < 0)) 4409 { 4410 ERR("invalid parameter 0x%08x\n", (DWORD)lParam); 4411 return FALSE; 4412 } 4413 4414 TRACE("%p, cx = %d, cy = %d\n", infoPtr->hwndSelf, cx, cy); 4415 4416 /* The documentation claims you can only change the button size before 4417 * any button has been added. But this is wrong. 4418 * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding 4419 * it to the toolbar, and it checks that the return value is nonzero - mjm 4420 * Further testing shows that we must actually perform the change too. 4421 */ 4422 /* 4423 * The documentation also does not mention that if 0 is supplied for 4424 * either size, the system changes it to the default of 24 wide and 4425 * 22 high. Demonstrated in ControlSpy Toolbar. GLA 3/02 4426 */ 4427 if (cx == 0) cx = 24; 4428 if (cy == 0) cy = 22; 4429 4430 cx = max(cx, infoPtr->szPadding.cx + infoPtr->nBitmapWidth); 4431 cy = max(cy, infoPtr->szPadding.cy + infoPtr->nBitmapHeight); 4432 4433 infoPtr->nButtonWidth = cx; 4434 infoPtr->nButtonHeight = cy; 4435 4436 infoPtr->iTopMargin = default_top_margin(infoPtr); 4437 TOOLBAR_LayoutToolbar(infoPtr); 4438 return TRUE; 4439 } 4440 4441 4442 static LRESULT 4443 TOOLBAR_SetButtonWidth (TOOLBAR_INFO *infoPtr, LPARAM lParam) 4444 { 4445 /* if setting to current values, ignore */ 4446 if ((infoPtr->cxMin == (short)LOWORD(lParam)) && 4447 (infoPtr->cxMax == (short)HIWORD(lParam))) { 4448 TRACE("matches current width, min=%d, max=%d, no recalc\n", 4449 infoPtr->cxMin, infoPtr->cxMax); 4450 return TRUE; 4451 } 4452 4453 /* save new values */ 4454 infoPtr->cxMin = (short)LOWORD(lParam); 4455 infoPtr->cxMax = (short)HIWORD(lParam); 4456 4457 /* otherwise we need to recalc the toolbar and in some cases 4458 recalc the bounding rectangle (does DrawText w/ DT_CALCRECT 4459 which doesn't actually draw - GA). */ 4460 TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n", 4461 infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax); 4462 4463 TOOLBAR_CalcToolbar (infoPtr); 4464 4465 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 4466 4467 return TRUE; 4468 } 4469 4470 4471 static LRESULT 4472 TOOLBAR_SetCmdId (TOOLBAR_INFO *infoPtr, INT nIndex, INT nId) 4473 { 4474 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 4475 return FALSE; 4476 4477 infoPtr->buttons[nIndex].idCommand = nId; 4478 4479 if (infoPtr->hwndToolTip) { 4480 4481 FIXME("change tool tip!\n"); 4482 4483 } 4484 4485 return TRUE; 4486 } 4487 4488 4489 static LRESULT 4490 TOOLBAR_SetDisabledImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 4491 { 4492 HIMAGELIST himlTemp; 4493 INT id = 0; 4494 4495 if (infoPtr->iVersion >= 5) 4496 id = wParam; 4497 4498 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis, 4499 &infoPtr->cimlDis, himl, id); 4500 4501 /* FIXME: redraw ? */ 4502 4503 return (LRESULT)himlTemp; 4504 } 4505 4506 4507 static LRESULT 4508 TOOLBAR_SetDrawTextFlags (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4509 { 4510 DWORD dwTemp; 4511 4512 TRACE("hwnd = %p, dwMask = 0x%08x, dwDTFlags = 0x%08x\n", infoPtr->hwndSelf, (DWORD)wParam, (DWORD)lParam); 4513 4514 dwTemp = infoPtr->dwDTFlags; 4515 infoPtr->dwDTFlags = 4516 (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam; 4517 4518 return (LRESULT)dwTemp; 4519 } 4520 4521 /* This function differs a bit from what MSDN says it does: 4522 * 1. lParam contains extended style flags to OR with current style 4523 * (MSDN isn't clear on the OR bit) 4524 * 2. wParam appears to contain extended style flags to be reset 4525 * (MSDN says that this parameter is reserved) 4526 */ 4527 static LRESULT 4528 TOOLBAR_SetExtendedStyle (TOOLBAR_INFO *infoPtr, DWORD mask, DWORD style) 4529 { 4530 DWORD old_style = infoPtr->dwExStyle; 4531 4532 TRACE("mask=0x%08x, style=0x%08x\n", mask, style); 4533 4534 if (mask) 4535 infoPtr->dwExStyle = (old_style & ~mask) | (style & mask); 4536 else 4537 infoPtr->dwExStyle = style; 4538 4539 if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL) 4540 FIXME("Unknown Toolbar Extended Style 0x%08x. Please report.\n", 4541 (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)); 4542 4543 if ((old_style ^ infoPtr->dwExStyle) & TBSTYLE_EX_MIXEDBUTTONS) 4544 TOOLBAR_CalcToolbar(infoPtr); 4545 else 4546 TOOLBAR_LayoutToolbar(infoPtr); 4547 4548 TOOLBAR_AutoSize(infoPtr); 4549 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4550 4551 return old_style; 4552 } 4553 4554 4555 static LRESULT 4556 TOOLBAR_SetHotImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 4557 { 4558 HIMAGELIST himlTemp; 4559 INT id = 0; 4560 4561 if (infoPtr->iVersion >= 5) 4562 id = wParam; 4563 4564 TRACE("hwnd = %p, himl = %p, id = %d\n", infoPtr->hwndSelf, himl, id); 4565 4566 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot, 4567 &infoPtr->cimlHot, himl, id); 4568 4569 /* FIXME: redraw ? */ 4570 4571 return (LRESULT)himlTemp; 4572 } 4573 4574 4575 /* Makes previous hot button no longer hot, makes the specified 4576 * button hot and sends appropriate notifications. dwReason is one or 4577 * more HICF_ flags. Specify nHit < 0 to make no buttons hot. 4578 * NOTE 1: this function does not validate nHit 4579 * NOTE 2: the name of this function is completely made up and 4580 * not based on any documentation from Microsoft. */ 4581 static void 4582 TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason) 4583 { 4584 if (infoPtr->nHotItem != nHit) 4585 { 4586 NMTBHOTITEM nmhotitem; 4587 TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL; 4588 4589 nmhotitem.dwFlags = dwReason; 4590 if(infoPtr->nHotItem >= 0) 4591 { 4592 oldBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; 4593 nmhotitem.idOld = oldBtnPtr->idCommand; 4594 } 4595 else 4596 { 4597 nmhotitem.dwFlags |= HICF_ENTERING; 4598 nmhotitem.idOld = 0; 4599 } 4600 4601 if (nHit >= 0) 4602 { 4603 btnPtr = &infoPtr->buttons[nHit]; 4604 nmhotitem.idNew = btnPtr->idCommand; 4605 } 4606 else 4607 { 4608 nmhotitem.dwFlags |= HICF_LEAVING; 4609 nmhotitem.idNew = 0; 4610 } 4611 4612 /* now change the hot and invalidate the old and new buttons - if the 4613 * parent agrees */ 4614 if (!TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE)) 4615 { 4616 if (oldBtnPtr) { 4617 oldBtnPtr->bHot = FALSE; 4618 InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE); 4619 } 4620 /* setting disabled buttons as hot fails even if the notify contains the button id */ 4621 if (btnPtr && (btnPtr->fsState & TBSTATE_ENABLED)) { 4622 btnPtr->bHot = TRUE; 4623 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 4624 infoPtr->nHotItem = nHit; 4625 } 4626 else 4627 infoPtr->nHotItem = -1; 4628 } 4629 } 4630 } 4631 4632 static LRESULT 4633 TOOLBAR_SetHotItem (TOOLBAR_INFO *infoPtr, INT nHotItem) 4634 { 4635 INT nOldHotItem = infoPtr->nHotItem; 4636 4637 TRACE("hwnd = %p, nHotItem = %d\n", infoPtr->hwndSelf, nHotItem); 4638 4639 if (nHotItem >= infoPtr->nNumButtons) 4640 return infoPtr->nHotItem; 4641 4642 if (nHotItem < 0) 4643 nHotItem = -1; 4644 4645 /* NOTE: an application can still remove the hot item even if anchor 4646 * highlighting is enabled */ 4647 4648 TOOLBAR_SetHotItemEx(infoPtr, nHotItem, HICF_OTHER); 4649 4650 if (nOldHotItem < 0) 4651 return -1; 4652 4653 return (LRESULT)nOldHotItem; 4654 } 4655 4656 4657 static LRESULT 4658 TOOLBAR_SetImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 4659 { 4660 HIMAGELIST himlTemp; 4661 INT oldButtonWidth = infoPtr->nButtonWidth; 4662 INT oldBitmapWidth = infoPtr->nBitmapWidth; 4663 INT oldBitmapHeight = infoPtr->nBitmapHeight; 4664 INT i, id = 0; 4665 4666 if (infoPtr->iVersion >= 5) 4667 id = wParam; 4668 4669 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef, 4670 &infoPtr->cimlDef, himl, id); 4671 4672 infoPtr->nNumBitmaps = 0; 4673 for (i = 0; i < infoPtr->cimlDef; i++) 4674 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); 4675 4676 if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth, 4677 &infoPtr->nBitmapHeight)) 4678 { 4679 infoPtr->nBitmapWidth = 1; 4680 infoPtr->nBitmapHeight = 1; 4681 } 4682 if ((oldBitmapWidth != infoPtr->nBitmapWidth) || (oldBitmapHeight != infoPtr->nBitmapHeight)) 4683 { 4684 TOOLBAR_CalcToolbar(infoPtr); 4685 if (infoPtr->nButtonWidth < oldButtonWidth) 4686 TOOLBAR_SetButtonSize(infoPtr, MAKELONG(oldButtonWidth, infoPtr->nButtonHeight)); 4687 } 4688 4689 TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n", 4690 infoPtr->hwndSelf, infoPtr->himlDef, id, infoPtr->nNumBitmaps, 4691 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 4692 4693 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4694 4695 return (LRESULT)himlTemp; 4696 } 4697 4698 4699 static LRESULT 4700 TOOLBAR_SetIndent (TOOLBAR_INFO *infoPtr, INT nIndent) 4701 { 4702 infoPtr->nIndent = nIndent; 4703 4704 TRACE("\n"); 4705 4706 /* process only on indent changing */ 4707 if(infoPtr->nIndent != nIndent) 4708 { 4709 infoPtr->nIndent = nIndent; 4710 TOOLBAR_CalcToolbar (infoPtr); 4711 InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); 4712 } 4713 4714 return TRUE; 4715 } 4716 4717 4718 static LRESULT 4719 TOOLBAR_SetInsertMark (TOOLBAR_INFO *infoPtr, const TBINSERTMARK *lptbim) 4720 { 4721 TRACE("hwnd = %p, lptbim = { %d, 0x%08x}\n", infoPtr->hwndSelf, lptbim->iButton, lptbim->dwFlags); 4722 4723 if ((lptbim->dwFlags & ~TBIMHT_AFTER) != 0) 4724 { 4725 FIXME("Unrecognized flag(s): 0x%08x\n", (lptbim->dwFlags & ~TBIMHT_AFTER)); 4726 return 0; 4727 } 4728 4729 if ((lptbim->iButton == -1) || 4730 ((lptbim->iButton < infoPtr->nNumButtons) && 4731 (lptbim->iButton >= 0))) 4732 { 4733 infoPtr->tbim = *lptbim; 4734 /* FIXME: don't need to update entire toolbar */ 4735 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4736 } 4737 else 4738 ERR("Invalid button index %d\n", lptbim->iButton); 4739 4740 return 0; 4741 } 4742 4743 4744 static LRESULT 4745 TOOLBAR_SetInsertMarkColor (TOOLBAR_INFO *infoPtr, COLORREF clr) 4746 { 4747 infoPtr->clrInsertMark = clr; 4748 4749 /* FIXME: don't need to update entire toolbar */ 4750 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4751 4752 return 0; 4753 } 4754 4755 4756 static LRESULT 4757 TOOLBAR_SetMaxTextRows (TOOLBAR_INFO *infoPtr, INT nMaxRows) 4758 { 4759 infoPtr->nMaxTextRows = nMaxRows; 4760 4761 TOOLBAR_CalcToolbar(infoPtr); 4762 return TRUE; 4763 } 4764 4765 4766 static LRESULT 4767 TOOLBAR_SetMetrics (TOOLBAR_INFO *infoPtr, TBMETRICS *pMetrics) 4768 { 4769 BOOL changed = FALSE; 4770 4771 if (!pMetrics) 4772 return FALSE; 4773 4774 /* TODO: check if cbSize is a valid value */ 4775 4776 if (pMetrics->dwMask & TBMF_PAD) 4777 { 4778 infoPtr->szPadding.cx = pMetrics->cxPad; 4779 infoPtr->szPadding.cy = pMetrics->cyPad; 4780 changed = TRUE; 4781 } 4782 4783 if (pMetrics->dwMask & TBMF_PAD) 4784 { 4785 infoPtr->szBarPadding.cx = pMetrics->cxBarPad; 4786 infoPtr->szBarPadding.cy = pMetrics->cyBarPad; 4787 changed = TRUE; 4788 } 4789 4790 if (pMetrics->dwMask & TBMF_BUTTONSPACING) 4791 { 4792 infoPtr->szSpacing.cx = pMetrics->cxButtonSpacing; 4793 infoPtr->szSpacing.cy = pMetrics->cyButtonSpacing; 4794 changed = TRUE; 4795 } 4796 4797 if (changed) 4798 TOOLBAR_CalcToolbar(infoPtr); 4799 4800 return TRUE; 4801 } 4802 4803 /* MSDN gives slightly wrong info on padding. 4804 * 1. It is not only used on buttons with the BTNS_AUTOSIZE style 4805 * 2. It is not used to create a blank area between the edge of the button 4806 * and the text or image if TBSTYLE_LIST is set. It is used to control 4807 * the gap between the image and text. 4808 * 3. It is not applied to both sides. If TBSTYLE_LIST is set it is used 4809 * to control the bottom and right borders [with the border being 4810 * szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding 4811 * is shared evenly on both sides of the button. 4812 * See blueprints in comments above TOOLBAR_MeasureButton for more info. 4813 */ 4814 static LRESULT 4815 TOOLBAR_SetPadding (TOOLBAR_INFO *infoPtr, LPARAM lParam) 4816 { 4817 DWORD oldPad; 4818 4819 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); 4820 infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE)); 4821 infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE)); 4822 TRACE("cx=%d, cy=%d\n", 4823 infoPtr->szPadding.cx, infoPtr->szPadding.cy); 4824 return (LRESULT) oldPad; 4825 } 4826 4827 4828 static LRESULT 4829 TOOLBAR_SetParent (TOOLBAR_INFO *infoPtr, HWND hParent) 4830 { 4831 HWND hwndOldNotify; 4832 4833 TRACE("\n"); 4834 4835 hwndOldNotify = infoPtr->hwndNotify; 4836 infoPtr->hwndNotify = hParent; 4837 4838 return (LRESULT)hwndOldNotify; 4839 } 4840 4841 4842 static LRESULT 4843 TOOLBAR_SetRows (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPRECT lprc) 4844 { 4845 int rows = LOWORD(wParam); 4846 BOOL bLarger = HIWORD(wParam); 4847 4848 TRACE("\n"); 4849 4850 TRACE("Setting rows to %d (%d)\n", rows, bLarger); 4851 4852 if(infoPtr->nRows != rows) 4853 { 4854 TBUTTON_INFO *btnPtr = infoPtr->buttons; 4855 int curColumn = 0; /* Current column */ 4856 int curRow = 0; /* Current row */ 4857 int hidden = 0; /* Number of hidden buttons */ 4858 int seps = 0; /* Number of separators */ 4859 int idealWrap = 0; /* Ideal wrap point */ 4860 int i; 4861 BOOL wrap; 4862 4863 /* 4864 Calculate new size and wrap points - Under windows, setrows will 4865 change the dimensions if needed to show the number of requested 4866 rows (if CCS_NORESIZE is set), or will take up the whole window 4867 (if no CCS_NORESIZE). 4868 4869 Basic algorithm - If N buttons, and y rows requested, each row 4870 contains N/y buttons. 4871 4872 FIXME: Handling of separators not obvious from testing results 4873 FIXME: Take width of window into account? 4874 */ 4875 4876 /* Loop through the buttons one by one counting key items */ 4877 for (i = 0; i < infoPtr->nNumButtons; i++ ) 4878 { 4879 btnPtr[i].fsState &= ~TBSTATE_WRAP; 4880 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 4881 hidden++; 4882 else if (btnPtr[i].fsStyle & BTNS_SEP) 4883 seps++; 4884 } 4885 4886 /* FIXME: Separators make this quite complex */ 4887 if (seps) FIXME("Separators unhandled\n"); 4888 4889 /* Round up so more per line, i.e., less rows */ 4890 idealWrap = (infoPtr->nNumButtons - hidden + (rows-1)) / (rows ? rows : 1); 4891 4892 /* Calculate ideal wrap point if we are allowed to grow, but cannot 4893 achieve the requested number of rows. */ 4894 if (bLarger && idealWrap > 1) 4895 { 4896 int resRows = (infoPtr->nNumButtons + (idealWrap-1)) / idealWrap; 4897 int moreRows = (infoPtr->nNumButtons + (idealWrap-2)) / (idealWrap-1); 4898 4899 if (resRows < rows && moreRows > rows) 4900 { 4901 idealWrap--; 4902 TRACE("Changing idealWrap due to bLarger (now %d)\n", idealWrap); 4903 } 4904 } 4905 4906 curColumn = curRow = 0; 4907 wrap = FALSE; 4908 TRACE("Trying to wrap at %d (%d,%d,%d)\n", idealWrap, 4909 infoPtr->nNumButtons, hidden, rows); 4910 4911 for (i = 0; i < infoPtr->nNumButtons; i++ ) 4912 { 4913 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 4914 continue; 4915 4916 /* Step on, wrap if necessary or flag next to wrap */ 4917 if (!wrap) { 4918 curColumn++; 4919 } else { 4920 wrap = FALSE; 4921 curColumn = 1; 4922 curRow++; 4923 } 4924 4925 if (curColumn > (idealWrap-1)) { 4926 wrap = TRUE; 4927 btnPtr[i].fsState |= TBSTATE_WRAP; 4928 } 4929 } 4930 4931 TRACE("Result - %d rows\n", curRow + 1); 4932 4933 /* recalculate toolbar */ 4934 TOOLBAR_CalcToolbar (infoPtr); 4935 4936 /* Resize if necessary (Only if NORESIZE is set - odd, but basically 4937 if NORESIZE is NOT set, then the toolbar will always be resized to 4938 take up the whole window. With it set, sizing needs to be manual. */ 4939 if (infoPtr->dwStyle & CCS_NORESIZE) { 4940 SetWindowPos(infoPtr->hwndSelf, NULL, 0, 0, 4941 infoPtr->rcBound.right - infoPtr->rcBound.left, 4942 infoPtr->rcBound.bottom - infoPtr->rcBound.top, 4943 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 4944 } 4945 4946 /* repaint toolbar */ 4947 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 4948 } 4949 4950 /* return bounding rectangle */ 4951 if (lprc) { 4952 lprc->left = infoPtr->rcBound.left; 4953 lprc->right = infoPtr->rcBound.right; 4954 lprc->top = infoPtr->rcBound.top; 4955 lprc->bottom = infoPtr->rcBound.bottom; 4956 } 4957 4958 return 0; 4959 } 4960 4961 4962 static LRESULT 4963 TOOLBAR_SetState (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 4964 { 4965 TBUTTON_INFO *btnPtr; 4966 INT nIndex; 4967 4968 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 4969 if (nIndex == -1) 4970 return FALSE; 4971 4972 btnPtr = &infoPtr->buttons[nIndex]; 4973 4974 /* if hidden state has changed the invalidate entire window and recalc */ 4975 if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) { 4976 btnPtr->fsState = LOWORD(lParam); 4977 TOOLBAR_CalcToolbar (infoPtr); 4978 InvalidateRect(infoPtr->hwndSelf, 0, TRUE); 4979 return TRUE; 4980 } 4981 4982 /* process state changing if current state doesn't match new state */ 4983 if(btnPtr->fsState != LOWORD(lParam)) 4984 { 4985 btnPtr->fsState = LOWORD(lParam); 4986 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 4987 } 4988 4989 return TRUE; 4990 } 4991 4992 4993 static LRESULT 4994 TOOLBAR_SetStyle (TOOLBAR_INFO *infoPtr, DWORD style) 4995 { 4996 infoPtr->dwStyle = style; 4997 return 0; 4998 } 4999 5000 5001 static inline LRESULT 5002 TOOLBAR_SetToolTips (TOOLBAR_INFO *infoPtr, HWND hwndTooltip) 5003 { 5004 TRACE("hwnd=%p, hwndTooltip=%p\n", infoPtr->hwndSelf, hwndTooltip); 5005 5006 infoPtr->hwndToolTip = hwndTooltip; 5007 return 0; 5008 } 5009 5010 5011 static LRESULT 5012 TOOLBAR_SetUnicodeFormat (TOOLBAR_INFO *infoPtr, WPARAM wParam) 5013 { 5014 BOOL bTemp; 5015 5016 TRACE("%s hwnd=%p\n", 5017 ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf); 5018 5019 bTemp = infoPtr->bUnicode; 5020 infoPtr->bUnicode = (BOOL)wParam; 5021 5022 return bTemp; 5023 } 5024 5025 5026 static LRESULT 5027 TOOLBAR_GetColorScheme (const TOOLBAR_INFO *infoPtr, LPCOLORSCHEME lParam) 5028 { 5029 lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 5030 comctl32_color.clrBtnHighlight : 5031 infoPtr->clrBtnHighlight; 5032 lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 5033 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 5034 return 1; 5035 } 5036 5037 5038 static LRESULT 5039 TOOLBAR_SetColorScheme (TOOLBAR_INFO *infoPtr, const COLORSCHEME *lParam) 5040 { 5041 TRACE("new colors Hl=%x Shd=%x, old colors Hl=%x Shd=%x\n", 5042 lParam->clrBtnHighlight, lParam->clrBtnShadow, 5043 infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow); 5044 5045 infoPtr->clrBtnHighlight = lParam->clrBtnHighlight; 5046 infoPtr->clrBtnShadow = lParam->clrBtnShadow; 5047 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 5048 return 0; 5049 } 5050 5051 5052 static LRESULT 5053 TOOLBAR_SetVersion (TOOLBAR_INFO *infoPtr, INT iVersion) 5054 { 5055 INT iOldVersion = infoPtr->iVersion; 5056 5057 infoPtr->iVersion = iVersion; 5058 5059 if (infoPtr->iVersion >= 5) 5060 TOOLBAR_SetUnicodeFormat(infoPtr, TRUE); 5061 5062 return iOldVersion; 5063 } 5064 5065 5066 static LRESULT 5067 TOOLBAR_GetStringA (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPSTR str) 5068 { 5069 WORD iString = HIWORD(wParam); 5070 WORD buffersize = LOWORD(wParam); 5071 LRESULT ret = -1; 5072 5073 TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", infoPtr->hwndSelf, iString, buffersize, str); 5074 5075 if (iString < infoPtr->nNumStrings) 5076 { 5077 ret = WideCharToMultiByte(CP_ACP, 0, infoPtr->strings[iString], -1, str, buffersize, NULL, NULL); 5078 ret--; 5079 5080 TRACE("returning %s\n", debugstr_a(str)); 5081 } 5082 else 5083 WARN("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); 5084 5085 return ret; 5086 } 5087 5088 5089 static LRESULT 5090 TOOLBAR_GetStringW (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPWSTR str) 5091 { 5092 WORD iString = HIWORD(wParam); 5093 WORD len = LOWORD(wParam)/sizeof(WCHAR) - 1; 5094 LRESULT ret = -1; 5095 5096 TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", infoPtr->hwndSelf, iString, LOWORD(wParam), str); 5097 5098 if (iString < infoPtr->nNumStrings) 5099 { 5100 len = min(len, strlenW(infoPtr->strings[iString])); 5101 ret = (len+1)*sizeof(WCHAR); 5102 if (str) 5103 { 5104 memcpy(str, infoPtr->strings[iString], ret); 5105 str[len] = '\0'; 5106 } 5107 ret = len; 5108 5109 TRACE("returning %s\n", debugstr_w(str)); 5110 } 5111 else 5112 WARN("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); 5113 5114 return ret; 5115 } 5116 5117 /* UNDOCUMENTED MESSAGE: This appears to set some kind of size. Perhaps it 5118 * is the maximum size of the toolbar? */ 5119 static LRESULT TOOLBAR_Unkwn45D(HWND hwnd, WPARAM wParam, LPARAM lParam) 5120 { 5121 SIZE * pSize = (SIZE*)lParam; 5122 FIXME("hwnd=%p, wParam=0x%08lx, size.cx=%d, size.cy=%d stub!\n", hwnd, wParam, pSize->cx, pSize->cy); 5123 return 0; 5124 } 5125 5126 5127 /* This is an extended version of the TB_SETHOTITEM message. It allows the 5128 * caller to specify a reason why the hot item changed (rather than just the 5129 * HICF_OTHER that TB_SETHOTITEM sends). */ 5130 static LRESULT 5131 TOOLBAR_SetHotItem2 (TOOLBAR_INFO *infoPtr, INT nHotItem, LPARAM lParam) 5132 { 5133 INT nOldHotItem = infoPtr->nHotItem; 5134 5135 TRACE("old item=%d, new item=%d, flags=%08x\n", 5136 nOldHotItem, nHotItem, (DWORD)lParam); 5137 5138 if (nHotItem < 0 || nHotItem > infoPtr->nNumButtons) 5139 nHotItem = -1; 5140 5141 /* NOTE: an application can still remove the hot item even if anchor 5142 * highlighting is enabled */ 5143 5144 TOOLBAR_SetHotItemEx(infoPtr, nHotItem, lParam); 5145 5146 GetFocus(); 5147 5148 return (nOldHotItem < 0) ? -1 : (LRESULT)nOldHotItem; 5149 } 5150 5151 /* Sets the toolbar global iListGap parameter which controls the amount of 5152 * spacing between the image and the text of buttons for TBSTYLE_LIST 5153 * toolbars. */ 5154 static LRESULT TOOLBAR_SetListGap(TOOLBAR_INFO *infoPtr, INT iListGap) 5155 { 5156 TRACE("hwnd=%p iListGap=%d\n", infoPtr->hwndSelf, iListGap); 5157 5158 infoPtr->iListGap = iListGap; 5159 5160 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 5161 5162 return 0; 5163 } 5164 5165 /* Returns the number of maximum number of image lists associated with the 5166 * various states. */ 5167 static LRESULT TOOLBAR_GetImageListCount(const TOOLBAR_INFO *infoPtr) 5168 { 5169 TRACE("hwnd=%p\n", infoPtr->hwndSelf); 5170 5171 return max(infoPtr->cimlDef, max(infoPtr->cimlHot, infoPtr->cimlDis)); 5172 } 5173 5174 static LRESULT 5175 TOOLBAR_GetIdealSize (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5176 { 5177 LPSIZE lpsize = (LPSIZE)lParam; 5178 5179 if (lpsize == NULL) 5180 return FALSE; 5181 5182 /* 5183 * Testing shows the following: 5184 * wParam = 0 adjust cx value 5185 * = 1 set cy value to max size. 5186 * lParam pointer to SIZE structure 5187 * 5188 */ 5189 TRACE("wParam %ld, lParam 0x%08lx -> 0x%08x 0x%08x\n", 5190 wParam, lParam, lpsize->cx, lpsize->cy); 5191 5192 switch(wParam) { 5193 case 0: 5194 if (lpsize->cx == -1) { 5195 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 5196 } 5197 else if(HIWORD(lpsize->cx)) { 5198 RECT rc; 5199 HWND hwndParent = GetParent(infoPtr->hwndSelf); 5200 5201 GetWindowRect(infoPtr->hwndSelf, &rc); 5202 MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2); 5203 TRACE("mapped to (%s)\n", wine_dbgstr_rect(&rc)); 5204 lpsize->cx = max(rc.right-rc.left, 5205 infoPtr->rcBound.right - infoPtr->rcBound.left); 5206 } 5207 else { 5208 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 5209 } 5210 break; 5211 case 1: 5212 lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 5213 break; 5214 default: 5215 FIXME("Unknown wParam %ld\n", wParam); 5216 return 0; 5217 } 5218 TRACE("set to -> 0x%08x 0x%08x\n", 5219 lpsize->cx, lpsize->cy); 5220 return 1; 5221 } 5222 5223 static LRESULT TOOLBAR_Unkwn464(HWND hwnd, WPARAM wParam, LPARAM lParam) 5224 { 5225 FIXME("hwnd=%p wParam %08lx lParam %08lx\n", hwnd, wParam, lParam); 5226 5227 InvalidateRect(hwnd, NULL, TRUE); 5228 return 1; 5229 } 5230 5231 5232 static LRESULT 5233 TOOLBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs) 5234 { 5235 TOOLBAR_INFO *infoPtr = (TOOLBAR_INFO *)GetWindowLongPtrW(hwnd, 0); 5236 LOGFONTW logFont; 5237 5238 TRACE("hwnd = %p, style=0x%08x\n", hwnd, lpcs->style); 5239 5240 infoPtr->dwStyle = GetWindowLongW(hwnd, GWL_STYLE); 5241 GetClientRect(hwnd, &infoPtr->client_rect); 5242 infoPtr->bUnicode = infoPtr->hwndNotify && 5243 (NFR_UNICODE == SendMessageW(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_REQUERY)); 5244 infoPtr->hwndToolTip = NULL; /* if needed the tooltip control will be created after a WM_MOUSEMOVE */ 5245 5246 SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); 5247 infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont); 5248 5249 OpenThemeData (hwnd, themeClass); 5250 5251 TOOLBAR_CheckStyle (infoPtr); 5252 5253 return 0; 5254 } 5255 5256 5257 static LRESULT 5258 TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr) 5259 { 5260 INT i; 5261 5262 /* delete tooltip control */ 5263 if (infoPtr->hwndToolTip) 5264 DestroyWindow (infoPtr->hwndToolTip); 5265 5266 /* delete temporary buffer for tooltip text */ 5267 Free (infoPtr->pszTooltipText); 5268 Free (infoPtr->bitmaps); /* bitmaps list */ 5269 5270 /* delete button data */ 5271 for (i = 0; i < infoPtr->nNumButtons; i++) 5272 if (TOOLBAR_ButtonHasString(&infoPtr->buttons[i])) 5273 Free ((LPWSTR)infoPtr->buttons[i].iString); 5274 Free (infoPtr->buttons); 5275 5276 /* delete strings */ 5277 if (infoPtr->strings) { 5278 for (i = 0; i < infoPtr->nNumStrings; i++) 5279 Free (infoPtr->strings[i]); 5280 5281 Free (infoPtr->strings); 5282 } 5283 5284 /* destroy internal image list */ 5285 if (infoPtr->himlInt) 5286 ImageList_Destroy (infoPtr->himlInt); 5287 5288 TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); 5289 TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); 5290 TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); 5291 5292 /* delete default font */ 5293 DeleteObject (infoPtr->hDefaultFont); 5294 5295 CloseThemeData (GetWindowTheme (infoPtr->hwndSelf)); 5296 5297 /* free toolbar info data */ 5298 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); 5299 Free (infoPtr); 5300 5301 return 0; 5302 } 5303 5304 5305 static LRESULT 5306 TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5307 { 5308 NMTBCUSTOMDRAW tbcd; 5309 INT ret = FALSE; 5310 DWORD ntfret; 5311 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 5312 DWORD dwEraseCustDraw = 0; 5313 5314 /* the app has told us not to redraw the toolbar */ 5315 if (!infoPtr->bDoRedraw) 5316 return FALSE; 5317 5318 if (infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) { 5319 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 5320 tbcd.nmcd.dwDrawStage = CDDS_PREERASE; 5321 tbcd.nmcd.hdc = (HDC)wParam; 5322 ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 5323 dwEraseCustDraw = ntfret & 0xffff; 5324 5325 /* FIXME: in general the return flags *can* be or'ed together */ 5326 switch (dwEraseCustDraw) 5327 { 5328 case CDRF_DODEFAULT: 5329 break; 5330 case CDRF_SKIPDEFAULT: 5331 return TRUE; 5332 default: 5333 FIXME("[%p] response %d not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n", 5334 infoPtr->hwndSelf, ntfret); 5335 } 5336 } 5337 5338 /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up 5339 * to my parent for processing. 5340 */ 5341 if (theme || (infoPtr->dwStyle & TBSTYLE_TRANSPARENT)) { 5342 POINT pt, ptorig; 5343 HDC hdc = (HDC)wParam; 5344 HWND parent; 5345 5346 pt.x = 0; 5347 pt.y = 0; 5348 parent = GetParent(infoPtr->hwndSelf); 5349 MapWindowPoints(infoPtr->hwndSelf, parent, &pt, 1); 5350 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); 5351 ret = SendMessageW (parent, WM_ERASEBKGND, wParam, lParam); 5352 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); 5353 } 5354 if (!ret) 5355 ret = DefWindowProcW (infoPtr->hwndSelf, WM_ERASEBKGND, wParam, lParam); 5356 5357 if (dwEraseCustDraw & CDRF_NOTIFYPOSTERASE) { 5358 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 5359 tbcd.nmcd.dwDrawStage = CDDS_POSTERASE; 5360 tbcd.nmcd.hdc = (HDC)wParam; 5361 ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 5362 dwEraseCustDraw = ntfret & 0xffff; 5363 switch (dwEraseCustDraw) 5364 { 5365 case CDRF_DODEFAULT: 5366 break; 5367 case CDRF_SKIPDEFAULT: 5368 return TRUE; 5369 default: 5370 FIXME("[%p] response %d not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)\n", 5371 infoPtr->hwndSelf, ntfret); 5372 } 5373 } 5374 return ret; 5375 } 5376 5377 5378 static inline LRESULT 5379 TOOLBAR_GetFont (const TOOLBAR_INFO *infoPtr) 5380 { 5381 return (LRESULT)infoPtr->hFont; 5382 } 5383 5384 5385 static void 5386 TOOLBAR_SetRelativeHotItem(TOOLBAR_INFO *infoPtr, INT iDirection, DWORD dwReason) 5387 { 5388 INT i; 5389 INT nNewHotItem = infoPtr->nHotItem; 5390 5391 for (i = 0; i < infoPtr->nNumButtons; i++) 5392 { 5393 /* did we wrap? */ 5394 if ((nNewHotItem + iDirection < 0) || 5395 (nNewHotItem + iDirection >= infoPtr->nNumButtons)) 5396 { 5397 NMTBWRAPHOTITEM nmtbwhi; 5398 nmtbwhi.idNew = infoPtr->buttons[nNewHotItem].idCommand; 5399 nmtbwhi.iDirection = iDirection; 5400 nmtbwhi.dwReason = dwReason; 5401 5402 if (TOOLBAR_SendNotify(&nmtbwhi.hdr, infoPtr, TBN_WRAPHOTITEM)) 5403 return; 5404 } 5405 5406 nNewHotItem += iDirection; 5407 nNewHotItem = (nNewHotItem + infoPtr->nNumButtons) % infoPtr->nNumButtons; 5408 5409 if ((infoPtr->buttons[nNewHotItem].fsState & TBSTATE_ENABLED) && 5410 !(infoPtr->buttons[nNewHotItem].fsStyle & BTNS_SEP)) 5411 { 5412 TOOLBAR_SetHotItemEx(infoPtr, nNewHotItem, dwReason); 5413 break; 5414 } 5415 } 5416 } 5417 5418 static LRESULT 5419 TOOLBAR_KeyDown (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5420 { 5421 NMKEY nmkey; 5422 5423 nmkey.nVKey = (UINT)wParam; 5424 nmkey.uFlags = HIWORD(lParam); 5425 5426 if (TOOLBAR_SendNotify(&nmkey.hdr, infoPtr, NM_KEYDOWN)) 5427 return DefWindowProcW(infoPtr->hwndSelf, WM_KEYDOWN, wParam, lParam); 5428 5429 switch ((UINT)wParam) 5430 { 5431 case VK_LEFT: 5432 case VK_UP: 5433 TOOLBAR_SetRelativeHotItem(infoPtr, -1, HICF_ARROWKEYS); 5434 break; 5435 case VK_RIGHT: 5436 case VK_DOWN: 5437 TOOLBAR_SetRelativeHotItem(infoPtr, 1, HICF_ARROWKEYS); 5438 break; 5439 case VK_SPACE: 5440 case VK_RETURN: 5441 if ((infoPtr->nHotItem >= 0) && 5442 (infoPtr->buttons[infoPtr->nHotItem].fsState & TBSTATE_ENABLED)) 5443 { 5444 SendMessageW (infoPtr->hwndNotify, WM_COMMAND, 5445 MAKEWPARAM(infoPtr->buttons[infoPtr->nHotItem].idCommand, BN_CLICKED), 5446 (LPARAM)infoPtr->hwndSelf); 5447 } 5448 break; 5449 } 5450 5451 return 0; 5452 } 5453 5454 5455 static LRESULT 5456 TOOLBAR_LButtonDblClk (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5457 { 5458 POINT pt; 5459 BOOL button; 5460 5461 pt.x = (short)LOWORD(lParam); 5462 pt.y = (short)HIWORD(lParam); 5463 TOOLBAR_InternalHitTest (infoPtr, &pt, &button); 5464 5465 if (button) 5466 TOOLBAR_LButtonDown (infoPtr, wParam, lParam); 5467 else if (infoPtr->dwStyle & CCS_ADJUSTABLE) 5468 TOOLBAR_Customize (infoPtr); 5469 5470 return 0; 5471 } 5472 5473 5474 static LRESULT 5475 TOOLBAR_LButtonDown (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5476 { 5477 TBUTTON_INFO *btnPtr; 5478 POINT pt; 5479 INT nHit; 5480 NMTOOLBARA nmtb; 5481 NMMOUSE nmmouse; 5482 BOOL bDragKeyPressed; 5483 BOOL button; 5484 5485 TRACE("\n"); 5486 5487 if (infoPtr->dwStyle & TBSTYLE_ALTDRAG) 5488 bDragKeyPressed = (GetKeyState(VK_MENU) < 0); 5489 else 5490 bDragKeyPressed = (wParam & MK_SHIFT); 5491 5492 if (infoPtr->hwndToolTip) 5493 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 5494 WM_LBUTTONDOWN, wParam, lParam); 5495 5496 pt.x = (short)LOWORD(lParam); 5497 pt.y = (short)HIWORD(lParam); 5498 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt, &button); 5499 5500 if (button) 5501 btnPtr = &infoPtr->buttons[nHit]; 5502 5503 if (button && bDragKeyPressed && (infoPtr->dwStyle & CCS_ADJUSTABLE)) 5504 { 5505 infoPtr->nButtonDrag = nHit; 5506 SetCapture (infoPtr->hwndSelf); 5507 5508 /* If drag cursor has not been loaded, load it. 5509 * Note: it doesn't need to be freed */ 5510 if (!hCursorDrag) 5511 hCursorDrag = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_MOVEBUTTON); 5512 SetCursor(hCursorDrag); 5513 } 5514 else if (button) 5515 { 5516 RECT arrowRect; 5517 infoPtr->nOldHit = nHit; 5518 5519 CopyRect(&arrowRect, &btnPtr->rect); 5520 arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH); 5521 5522 /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */ 5523 if ((btnPtr->fsState & TBSTATE_ENABLED) && 5524 ((btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) || 5525 ((btnPtr->fsStyle & BTNS_DROPDOWN) && 5526 ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) || 5527 (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle)))))) 5528 { 5529 LRESULT res; 5530 5531 /* draw in pressed state */ 5532 if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) 5533 btnPtr->fsState |= TBSTATE_PRESSED; 5534 else 5535 btnPtr->bDropDownPressed = TRUE; 5536 RedrawWindow(infoPtr->hwndSelf,&btnPtr->rect,0, 5537 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); 5538 5539 memset(&nmtb, 0, sizeof(nmtb)); 5540 nmtb.iItem = btnPtr->idCommand; 5541 nmtb.rcButton = btnPtr->rect; 5542 res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, 5543 TBN_DROPDOWN); 5544 TRACE("TBN_DROPDOWN responded with %ld\n", res); 5545 5546 if (res != TBDDRET_TREATPRESSED) 5547 { 5548 MSG msg; 5549 5550 /* redraw button in unpressed state */ 5551 if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) 5552 btnPtr->fsState &= ~TBSTATE_PRESSED; 5553 else 5554 btnPtr->bDropDownPressed = FALSE; 5555 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 5556 5557 /* find and set hot item */ 5558 GetCursorPos(&pt); 5559 ScreenToClient(infoPtr->hwndSelf, &pt); 5560 nHit = TOOLBAR_InternalHitTest(infoPtr, &pt, &button); 5561 if (!infoPtr->bAnchor || button) 5562 TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE | HICF_LMOUSE); 5563 5564 /* remove any left mouse button down or double-click messages 5565 * so that we can get a toggle effect on the button */ 5566 while (PeekMessageW(&msg, infoPtr->hwndSelf, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE) || 5567 PeekMessageW(&msg, infoPtr->hwndSelf, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE)) 5568 ; 5569 5570 return 0; 5571 } 5572 /* otherwise drop through and process as pushed */ 5573 } 5574 infoPtr->bCaptured = TRUE; 5575 infoPtr->nButtonDown = nHit; 5576 infoPtr->bDragOutSent = FALSE; 5577 5578 btnPtr->fsState |= TBSTATE_PRESSED; 5579 5580 TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE | HICF_LMOUSE); 5581 5582 if (btnPtr->fsState & TBSTATE_ENABLED) 5583 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 5584 UpdateWindow(infoPtr->hwndSelf); 5585 SetCapture (infoPtr->hwndSelf); 5586 } 5587 5588 if (button) 5589 { 5590 memset(&nmtb, 0, sizeof(nmtb)); 5591 nmtb.iItem = btnPtr->idCommand; 5592 TOOLBAR_SendNotify((NMHDR *)&nmtb, infoPtr, TBN_BEGINDRAG); 5593 } 5594 5595 nmmouse.dwHitInfo = nHit; 5596 5597 /* !!! Undocumented - sends NM_LDOWN with the NMMOUSE structure. */ 5598 if (!button) 5599 nmmouse.dwItemSpec = -1; 5600 else 5601 { 5602 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 5603 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 5604 } 5605 5606 ClientToScreen(infoPtr->hwndSelf, &pt); 5607 nmmouse.pt = pt; 5608 5609 if (!TOOLBAR_SendNotify(&nmmouse.hdr, infoPtr, NM_LDOWN)) 5610 return DefWindowProcW(infoPtr->hwndSelf, WM_LBUTTONDOWN, wParam, lParam); 5611 5612 return 0; 5613 } 5614 5615 static LRESULT 5616 TOOLBAR_LButtonUp (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5617 { 5618 TBUTTON_INFO *btnPtr; 5619 POINT pt; 5620 INT nHit; 5621 INT nOldIndex = -1; 5622 NMHDR hdr; 5623 NMMOUSE nmmouse; 5624 NMTOOLBARA nmtb; 5625 BOOL button; 5626 5627 if (infoPtr->hwndToolTip) 5628 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 5629 WM_LBUTTONUP, wParam, lParam); 5630 5631 pt.x = (short)LOWORD(lParam); 5632 pt.y = (short)HIWORD(lParam); 5633 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt, &button); 5634 5635 if (!infoPtr->bAnchor || button) 5636 TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE | HICF_LMOUSE); 5637 5638 if (infoPtr->nButtonDrag >= 0) { 5639 RECT rcClient; 5640 NMHDR hdr; 5641 5642 btnPtr = &infoPtr->buttons[infoPtr->nButtonDrag]; 5643 ReleaseCapture(); 5644 /* reset cursor */ 5645 SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); 5646 5647 GetClientRect(infoPtr->hwndSelf, &rcClient); 5648 if (PtInRect(&rcClient, pt)) 5649 { 5650 INT nButton = -1; 5651 if (nHit >= 0) 5652 nButton = nHit; 5653 else if (nHit < -1) 5654 nButton = -nHit; 5655 else if ((nHit == -1) && PtInRect(&infoPtr->buttons[-nHit].rect, pt)) 5656 nButton = -nHit; 5657 5658 if (nButton == infoPtr->nButtonDrag) 5659 { 5660 /* if the button is moved sightly left and we have a 5661 * separator there then remove it */ 5662 if (pt.x < (btnPtr->rect.left + (btnPtr->rect.right - btnPtr->rect.left)/2)) 5663 { 5664 if ((nButton > 0) && (infoPtr->buttons[nButton-1].fsStyle & BTNS_SEP)) 5665 TOOLBAR_DeleteButton(infoPtr, nButton - 1); 5666 } 5667 else /* else insert a separator before the dragged button */ 5668 { 5669 TBBUTTON tbb; 5670 memset(&tbb, 0, sizeof(tbb)); 5671 tbb.fsStyle = BTNS_SEP; 5672 tbb.iString = -1; 5673 TOOLBAR_InsertButtonT(infoPtr, nButton, &tbb, TRUE); 5674 } 5675 } 5676 else 5677 { 5678 if (nButton == -1) 5679 { 5680 if ((infoPtr->nNumButtons > 0) && (pt.x < infoPtr->buttons[0].rect.left)) 5681 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, 0); 5682 else 5683 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, infoPtr->nNumButtons); 5684 } 5685 else 5686 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, nButton); 5687 } 5688 } 5689 else 5690 { 5691 TRACE("button %d dragged out of toolbar\n", infoPtr->nButtonDrag); 5692 TOOLBAR_DeleteButton(infoPtr, infoPtr->nButtonDrag); 5693 } 5694 5695 /* button under cursor changed so need to re-set hot item */ 5696 TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE | HICF_LMOUSE); 5697 infoPtr->nButtonDrag = -1; 5698 5699 TOOLBAR_SendNotify(&hdr, infoPtr, TBN_TOOLBARCHANGE); 5700 } 5701 else if (infoPtr->nButtonDown >= 0) { 5702 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 5703 btnPtr->fsState &= ~TBSTATE_PRESSED; 5704 5705 if (btnPtr->fsStyle & BTNS_CHECK) { 5706 if (btnPtr->fsStyle & BTNS_GROUP) { 5707 nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, 5708 nHit); 5709 if ((nOldIndex != nHit) && 5710 (nOldIndex != -1)) 5711 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; 5712 btnPtr->fsState |= TBSTATE_CHECKED; 5713 } 5714 else { 5715 if (btnPtr->fsState & TBSTATE_CHECKED) 5716 btnPtr->fsState &= ~TBSTATE_CHECKED; 5717 else 5718 btnPtr->fsState |= TBSTATE_CHECKED; 5719 } 5720 } 5721 5722 if (nOldIndex != -1) 5723 InvalidateRect(infoPtr->hwndSelf, &infoPtr->buttons[nOldIndex].rect, TRUE); 5724 5725 /* 5726 * now we can ReleaseCapture, which triggers CAPTURECHANGED msg, 5727 * that resets bCaptured and btn TBSTATE_PRESSED flags, 5728 * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged) 5729 */ 5730 if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) 5731 ReleaseCapture (); 5732 infoPtr->nButtonDown = -1; 5733 5734 /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */ 5735 TOOLBAR_SendNotify (&hdr, infoPtr, 5736 NM_RELEASEDCAPTURE); 5737 5738 memset(&nmtb, 0, sizeof(nmtb)); 5739 nmtb.iItem = btnPtr->idCommand; 5740 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, 5741 TBN_ENDDRAG); 5742 5743 if (btnPtr->fsState & TBSTATE_ENABLED) 5744 { 5745 SendMessageW (infoPtr->hwndNotify, WM_COMMAND, 5746 MAKEWPARAM(infoPtr->buttons[nHit].idCommand, BN_CLICKED), (LPARAM)infoPtr->hwndSelf); 5747 5748 /* In case we have just been destroyed... */ 5749 if(!IsWindow(infoPtr->hwndSelf)) 5750 return 0; 5751 } 5752 } 5753 5754 /* !!! Undocumented - toolbar at 4.71 level and above sends 5755 * NM_CLICK with the NMMOUSE structure. */ 5756 nmmouse.dwHitInfo = nHit; 5757 5758 if (!button) 5759 nmmouse.dwItemSpec = -1; 5760 else 5761 { 5762 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 5763 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 5764 } 5765 5766 ClientToScreen(infoPtr->hwndSelf, &pt); 5767 nmmouse.pt = pt; 5768 5769 if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_CLICK)) 5770 return DefWindowProcW(infoPtr->hwndSelf, WM_LBUTTONUP, wParam, lParam); 5771 5772 return 0; 5773 } 5774 5775 static LRESULT 5776 TOOLBAR_RButtonUp(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5777 { 5778 INT nHit; 5779 NMMOUSE nmmouse; 5780 POINT pt; 5781 BOOL button; 5782 5783 pt.x = (short)LOWORD(lParam); 5784 pt.y = (short)HIWORD(lParam); 5785 5786 nHit = TOOLBAR_InternalHitTest(infoPtr, &pt, &button); 5787 nmmouse.dwHitInfo = nHit; 5788 5789 if (!button) { 5790 nmmouse.dwItemSpec = -1; 5791 } else { 5792 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 5793 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 5794 } 5795 5796 ClientToScreen(infoPtr->hwndSelf, &pt); 5797 nmmouse.pt = pt; 5798 5799 if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_RCLICK)) 5800 return DefWindowProcW(infoPtr->hwndSelf, WM_RBUTTONUP, wParam, lParam); 5801 5802 return 0; 5803 } 5804 5805 static LRESULT 5806 TOOLBAR_RButtonDblClk( TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5807 { 5808 NMHDR nmhdr; 5809 5810 if (!TOOLBAR_SendNotify(&nmhdr, infoPtr, NM_RDBLCLK)) 5811 return DefWindowProcW(infoPtr->hwndSelf, WM_RBUTTONDBLCLK, wParam, lParam); 5812 5813 return 0; 5814 } 5815 5816 static LRESULT 5817 TOOLBAR_CaptureChanged(TOOLBAR_INFO *infoPtr) 5818 { 5819 TBUTTON_INFO *btnPtr; 5820 5821 infoPtr->bCaptured = FALSE; 5822 5823 if (infoPtr->nButtonDown >= 0) 5824 { 5825 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 5826 btnPtr->fsState &= ~TBSTATE_PRESSED; 5827 5828 infoPtr->nOldHit = -1; 5829 5830 if (btnPtr->fsState & TBSTATE_ENABLED) 5831 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 5832 } 5833 return 0; 5834 } 5835 5836 static LRESULT 5837 TOOLBAR_MouseLeave (TOOLBAR_INFO *infoPtr) 5838 { 5839 /* don't remove hot effects when in anchor highlighting mode or when a 5840 * drop-down button is pressed */ 5841 if (infoPtr->nHotItem >= 0 && !infoPtr->bAnchor) 5842 { 5843 TBUTTON_INFO *hotBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; 5844 if (!hotBtnPtr->bDropDownPressed) 5845 TOOLBAR_SetHotItemEx(infoPtr, TOOLBAR_NOWHERE, HICF_MOUSE); 5846 } 5847 5848 if (infoPtr->nOldHit < 0) 5849 return TRUE; 5850 5851 /* If the last button we were over is depressed then make it not */ 5852 /* depressed and redraw it */ 5853 if(infoPtr->nOldHit == infoPtr->nButtonDown) 5854 { 5855 TBUTTON_INFO *btnPtr; 5856 RECT rc1; 5857 5858 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 5859 5860 btnPtr->fsState &= ~TBSTATE_PRESSED; 5861 5862 rc1 = btnPtr->rect; 5863 InflateRect (&rc1, 1, 1); 5864 InvalidateRect (infoPtr->hwndSelf, &rc1, TRUE); 5865 } 5866 5867 if (infoPtr->bCaptured && !infoPtr->bDragOutSent) 5868 { 5869 NMTOOLBARW nmt; 5870 ZeroMemory(&nmt, sizeof(nmt)); 5871 nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; 5872 TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); 5873 infoPtr->bDragOutSent = TRUE; 5874 } 5875 5876 infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */ 5877 5878 return TRUE; 5879 } 5880 5881 static LRESULT 5882 TOOLBAR_MouseMove (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 5883 { 5884 POINT pt; 5885 TRACKMOUSEEVENT trackinfo; 5886 INT nHit; 5887 TBUTTON_INFO *btnPtr; 5888 BOOL button; 5889 5890 if ((infoPtr->dwStyle & TBSTYLE_TOOLTIPS) && (infoPtr->hwndToolTip == NULL)) 5891 TOOLBAR_TooltipCreateControl(infoPtr); 5892 5893 if ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) { 5894 /* fill in the TRACKMOUSEEVENT struct */ 5895 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); 5896 trackinfo.dwFlags = TME_QUERY; 5897 5898 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ 5899 _TrackMouseEvent(&trackinfo); 5900 5901 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ 5902 if(trackinfo.hwndTrack != infoPtr->hwndSelf || !(trackinfo.dwFlags & TME_LEAVE)) { 5903 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ 5904 trackinfo.hwndTrack = infoPtr->hwndSelf; 5905 5906 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ 5907 /* and can properly deactivate the hot toolbar button */ 5908 _TrackMouseEvent(&trackinfo); 5909 } 5910 } 5911 5912 if (infoPtr->hwndToolTip) 5913 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 5914 WM_MOUSEMOVE, wParam, lParam); 5915 5916 pt.x = (short)LOWORD(lParam); 5917 pt.y = (short)HIWORD(lParam); 5918 5919 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt, &button); 5920 5921 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 5922 && (!infoPtr->bAnchor || button)) 5923 TOOLBAR_SetHotItemEx(infoPtr, button ? nHit : TOOLBAR_NOWHERE, HICF_MOUSE); 5924 5925 if (infoPtr->nOldHit != nHit) 5926 { 5927 if (infoPtr->bCaptured) 5928 { 5929 if (!infoPtr->bDragOutSent) 5930 { 5931 NMTOOLBARW nmt; 5932 ZeroMemory(&nmt, sizeof(nmt)); 5933 nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; 5934 TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); 5935 infoPtr->bDragOutSent = TRUE; 5936 } 5937 5938 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 5939 if (infoPtr->nOldHit == infoPtr->nButtonDown) { 5940 btnPtr->fsState &= ~TBSTATE_PRESSED; 5941 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 5942 } 5943 else if (nHit == infoPtr->nButtonDown) { 5944 btnPtr->fsState |= TBSTATE_PRESSED; 5945 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 5946 } 5947 infoPtr->nOldHit = nHit; 5948 } 5949 } 5950 5951 return 0; 5952 } 5953 5954 5955 static inline LRESULT 5956 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) 5957 { 5958 /* if (wndPtr->dwStyle & CCS_NODIVIDER) */ 5959 return DefWindowProcW (hwnd, WM_NCACTIVATE, wParam, lParam); 5960 /* else */ 5961 /* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */ 5962 } 5963 5964 5965 static inline LRESULT 5966 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 5967 { 5968 if (!(GetWindowLongW(hwnd, GWL_STYLE) & CCS_NODIVIDER)) 5969 ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE); 5970 5971 return DefWindowProcW (hwnd, WM_NCCALCSIZE, wParam, lParam); 5972 } 5973 5974 5975 static LRESULT 5976 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, const CREATESTRUCTW *lpcs) 5977 { 5978 TOOLBAR_INFO *infoPtr; 5979 DWORD styleadd = 0; 5980 5981 /* allocate memory for info structure */ 5982 infoPtr = Alloc (sizeof(TOOLBAR_INFO)); 5983 SetWindowLongPtrW (hwnd, 0, (LONG_PTR)infoPtr); 5984 5985 /* paranoid!! */ 5986 infoPtr->dwStructSize = sizeof(TBBUTTON); 5987 infoPtr->nRows = 1; 5988 infoPtr->nWidth = 0; 5989 5990 /* initialize info structure */ 5991 infoPtr->nButtonWidth = 23; 5992 infoPtr->nButtonHeight = 22; 5993 infoPtr->nBitmapHeight = 16; 5994 infoPtr->nBitmapWidth = 16; 5995 5996 infoPtr->nMaxTextRows = 1; 5997 infoPtr->cxMin = -1; 5998 infoPtr->cxMax = -1; 5999 infoPtr->nNumBitmaps = 0; 6000 infoPtr->nNumStrings = 0; 6001 6002 infoPtr->bCaptured = FALSE; 6003 infoPtr->nButtonDown = -1; 6004 infoPtr->nButtonDrag = -1; 6005 infoPtr->nOldHit = -1; 6006 infoPtr->nHotItem = -1; 6007 infoPtr->hwndNotify = lpcs->hwndParent; 6008 infoPtr->dwDTFlags = (lpcs->style & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS: DT_CENTER | DT_END_ELLIPSIS; 6009 infoPtr->bAnchor = FALSE; /* no anchor highlighting */ 6010 infoPtr->bDragOutSent = FALSE; 6011 infoPtr->iVersion = 0; 6012 infoPtr->hwndSelf = hwnd; 6013 infoPtr->bDoRedraw = TRUE; 6014 infoPtr->clrBtnHighlight = CLR_DEFAULT; 6015 infoPtr->clrBtnShadow = CLR_DEFAULT; 6016 infoPtr->szPadding.cx = DEFPAD_CX; 6017 infoPtr->szPadding.cy = DEFPAD_CY; 6018 infoPtr->szSpacing.cx = DEFSPACE_CX; 6019 infoPtr->szSpacing.cy = DEFSPACE_CY; 6020 infoPtr->iListGap = DEFLISTGAP; 6021 infoPtr->iTopMargin = default_top_margin(infoPtr); 6022 infoPtr->dwStyle = lpcs->style; 6023 infoPtr->tbim.iButton = -1; 6024 6025 /* fix instance handle, if the toolbar was created by CreateToolbarEx() */ 6026 if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) { 6027 HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW (GetParent (hwnd), GWLP_HINSTANCE); 6028 SetWindowLongPtrW (hwnd, GWLP_HINSTANCE, (LONG_PTR)hInst); 6029 } 6030 6031 /* I think the code below is a bug, but it is the way that the native 6032 * controls seem to work. The effect is that if the user of TBSTYLE_FLAT 6033 * forgets to specify TBSTYLE_TRANSPARENT but does specify either 6034 * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control 6035 * does *not* set TBSTYLE_TRANSPARENT even though it should!!!! 6036 * Somehow, the only cases of this seem to be MFC programs. 6037 * 6038 * Note also that the addition of _TRANSPARENT occurs *only* here. It 6039 * does not occur in the WM_STYLECHANGING routine. 6040 * (Guy Albertelli 9/2001) 6041 * 6042 */ 6043 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 6044 && !(lpcs->style & TBSTYLE_TRANSPARENT)) 6045 styleadd |= TBSTYLE_TRANSPARENT; 6046 if (!(lpcs->style & (CCS_TOP | CCS_NOMOVEY))) { 6047 styleadd |= CCS_TOP; /* default to top */ 6048 SetWindowLongW (hwnd, GWL_STYLE, lpcs->style | styleadd); 6049 } 6050 6051 return DefWindowProcW (hwnd, WM_NCCREATE, wParam, (LPARAM)lpcs); 6052 } 6053 6054 6055 static LRESULT 6056 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam) 6057 { 6058 DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); 6059 RECT rcWindow; 6060 HDC hdc; 6061 6062 if (dwStyle & WS_MINIMIZE) 6063 return 0; /* Nothing to do */ 6064 6065 DefWindowProcW (hwnd, WM_NCPAINT, wParam, lParam); 6066 6067 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW))) 6068 return 0; 6069 6070 if (!(dwStyle & CCS_NODIVIDER)) 6071 { 6072 GetWindowRect (hwnd, &rcWindow); 6073 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 6074 if( dwStyle & WS_BORDER ) 6075 InflateRect (&rcWindow, -1, -1); 6076 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP); 6077 } 6078 6079 ReleaseDC( hwnd, hdc ); 6080 6081 return 0; 6082 } 6083 6084 6085 /* handles requests from the tooltip control on what text to display */ 6086 static LRESULT TOOLBAR_TTGetDispInfo (TOOLBAR_INFO *infoPtr, NMTTDISPINFOW *lpnmtdi) 6087 { 6088 int index = TOOLBAR_GetButtonIndex(infoPtr, lpnmtdi->hdr.idFrom, FALSE); 6089 6090 TRACE("button index = %d\n", index); 6091 6092 Free (infoPtr->pszTooltipText); 6093 infoPtr->pszTooltipText = NULL; 6094 6095 if (index < 0) 6096 return 0; 6097 6098 if (infoPtr->bUnicode) 6099 { 6100 WCHAR wszBuffer[INFOTIPSIZE+1]; 6101 NMTBGETINFOTIPW tbgit; 6102 unsigned int len; /* in chars */ 6103 6104 wszBuffer[0] = '\0'; 6105 wszBuffer[INFOTIPSIZE] = '\0'; 6106 6107 tbgit.pszText = wszBuffer; 6108 tbgit.cchTextMax = INFOTIPSIZE; 6109 tbgit.iItem = lpnmtdi->hdr.idFrom; 6110 tbgit.lParam = infoPtr->buttons[index].dwData; 6111 6112 TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPW); 6113 6114 TRACE("TBN_GETINFOTIPW - got string %s\n", debugstr_w(tbgit.pszText)); 6115 6116 len = strlenW(tbgit.pszText); 6117 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) 6118 { 6119 /* need to allocate temporary buffer in infoPtr as there 6120 * isn't enough space in buffer passed to us by the 6121 * tooltip control */ 6122 infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); 6123 if (infoPtr->pszTooltipText) 6124 { 6125 memcpy(infoPtr->pszTooltipText, tbgit.pszText, (len+1)*sizeof(WCHAR)); 6126 lpnmtdi->lpszText = infoPtr->pszTooltipText; 6127 return 0; 6128 } 6129 } 6130 else if (len > 0) 6131 { 6132 memcpy(lpnmtdi->lpszText, tbgit.pszText, (len+1)*sizeof(WCHAR)); 6133 return 0; 6134 } 6135 } 6136 else 6137 { 6138 CHAR szBuffer[INFOTIPSIZE+1]; 6139 NMTBGETINFOTIPA tbgit; 6140 unsigned int len; /* in chars */ 6141 6142 szBuffer[0] = '\0'; 6143 szBuffer[INFOTIPSIZE] = '\0'; 6144 6145 tbgit.pszText = szBuffer; 6146 tbgit.cchTextMax = INFOTIPSIZE; 6147 tbgit.iItem = lpnmtdi->hdr.idFrom; 6148 tbgit.lParam = infoPtr->buttons[index].dwData; 6149 6150 TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPA); 6151 6152 TRACE("TBN_GETINFOTIPA - got string %s\n", debugstr_a(tbgit.pszText)); 6153 6154 len = MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, NULL, 0); 6155 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])) 6156 { 6157 /* need to allocate temporary buffer in infoPtr as there 6158 * isn't enough space in buffer passed to us by the 6159 * tooltip control */ 6160 infoPtr->pszTooltipText = Alloc(len*sizeof(WCHAR)); 6161 if (infoPtr->pszTooltipText) 6162 { 6163 MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, infoPtr->pszTooltipText, len); 6164 lpnmtdi->lpszText = infoPtr->pszTooltipText; 6165 return 0; 6166 } 6167 } 6168 else if (tbgit.pszText && tbgit.pszText[0]) 6169 { 6170 MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, 6171 lpnmtdi->lpszText, sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])); 6172 return 0; 6173 } 6174 } 6175 6176 /* if button has text, but it is not shown then automatically 6177 * use that text as tooltip */ 6178 if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) && 6179 !(infoPtr->buttons[index].fsStyle & BTNS_SHOWTEXT)) 6180 { 6181 LPWSTR pszText = TOOLBAR_GetText(infoPtr, &infoPtr->buttons[index]); 6182 unsigned int len = pszText ? strlenW(pszText) : 0; 6183 6184 TRACE("using button hidden text %s\n", debugstr_w(pszText)); 6185 6186 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) 6187 { 6188 /* need to allocate temporary buffer in infoPtr as there 6189 * isn't enough space in buffer passed to us by the 6190 * tooltip control */ 6191 infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); 6192 if (infoPtr->pszTooltipText) 6193 { 6194 memcpy(infoPtr->pszTooltipText, pszText, (len+1)*sizeof(WCHAR)); 6195 lpnmtdi->lpszText = infoPtr->pszTooltipText; 6196 return 0; 6197 } 6198 } 6199 else if (len > 0) 6200 { 6201 memcpy(lpnmtdi->lpszText, pszText, (len+1)*sizeof(WCHAR)); 6202 return 0; 6203 } 6204 } 6205 6206 TRACE("Sending tooltip notification to %p\n", infoPtr->hwndNotify); 6207 6208 /* last resort: send notification on to app */ 6209 /* FIXME: find out what is really used here */ 6210 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmtdi->hdr.idFrom, (LPARAM)lpnmtdi); 6211 } 6212 6213 6214 static inline LRESULT 6215 TOOLBAR_Notify (TOOLBAR_INFO *infoPtr, LPNMHDR lpnmh) 6216 { 6217 switch (lpnmh->code) 6218 { 6219 case PGN_CALCSIZE: 6220 { 6221 LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lpnmh; 6222 6223 if (lppgc->dwFlag == PGF_CALCWIDTH) { 6224 lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left; 6225 TRACE("processed PGN_CALCSIZE, returning horz size = %d\n", 6226 lppgc->iWidth); 6227 } 6228 else { 6229 lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 6230 TRACE("processed PGN_CALCSIZE, returning vert size = %d\n", 6231 lppgc->iHeight); 6232 } 6233 return 0; 6234 } 6235 6236 case PGN_SCROLL: 6237 { 6238 LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lpnmh; 6239 6240 lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ? 6241 infoPtr->nButtonWidth : infoPtr->nButtonHeight; 6242 TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n", 6243 lppgs->iScroll, lppgs->iDir); 6244 return 0; 6245 } 6246 6247 case TTN_GETDISPINFOW: 6248 return TOOLBAR_TTGetDispInfo(infoPtr, (LPNMTTDISPINFOW)lpnmh); 6249 6250 case TTN_GETDISPINFOA: 6251 FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); 6252 return 0; 6253 6254 default: 6255 return 0; 6256 } 6257 } 6258 6259 6260 static LRESULT 6261 TOOLBAR_NotifyFormat(const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 6262 { 6263 LRESULT format; 6264 6265 TRACE("wParam = 0x%lx, lParam = 0x%08lx\n", wParam, lParam); 6266 6267 if (lParam == NF_QUERY) 6268 return NFR_UNICODE; 6269 6270 if (lParam == NF_REQUERY) { 6271 format = SendMessageW(infoPtr->hwndNotify, 6272 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); 6273 if ((format != NFR_ANSI) && (format != NFR_UNICODE)) { 6274 ERR("wrong response to WM_NOTIFYFORMAT (%ld), assuming ANSI\n", 6275 format); 6276 format = NFR_ANSI; 6277 } 6278 return format; 6279 } 6280 return 0; 6281 } 6282 6283 6284 static LRESULT 6285 TOOLBAR_Paint (TOOLBAR_INFO *infoPtr, WPARAM wParam) 6286 { 6287 HDC hdc; 6288 PAINTSTRUCT ps; 6289 6290 /* fill ps.rcPaint with a default rect */ 6291 ps.rcPaint = infoPtr->rcBound; 6292 6293 hdc = wParam==0 ? BeginPaint(infoPtr->hwndSelf, &ps) : (HDC)wParam; 6294 6295 TRACE("psrect=(%s)\n", wine_dbgstr_rect(&ps.rcPaint)); 6296 6297 TOOLBAR_Refresh (infoPtr, hdc, &ps); 6298 if (!wParam) EndPaint (infoPtr->hwndSelf, &ps); 6299 6300 return 0; 6301 } 6302 6303 6304 static LRESULT 6305 TOOLBAR_SetFocus (TOOLBAR_INFO *infoPtr) 6306 { 6307 TRACE("nHotItem = %d\n", infoPtr->nHotItem); 6308 6309 /* make first item hot */ 6310 if (infoPtr->nNumButtons > 0) 6311 TOOLBAR_SetHotItemEx(infoPtr, 0, HICF_OTHER); 6312 6313 return 0; 6314 } 6315 6316 static LRESULT 6317 TOOLBAR_SetFont(TOOLBAR_INFO *infoPtr, HFONT hFont, WORD Redraw) 6318 { 6319 TRACE("font=%p redraw=%d\n", hFont, Redraw); 6320 6321 if (hFont == 0) 6322 infoPtr->hFont = infoPtr->hDefaultFont; 6323 else 6324 infoPtr->hFont = hFont; 6325 6326 TOOLBAR_CalcToolbar(infoPtr); 6327 6328 if (Redraw) 6329 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 6330 return 1; 6331 } 6332 6333 static LRESULT 6334 TOOLBAR_SetRedraw (TOOLBAR_INFO *infoPtr, WPARAM wParam) 6335 /***************************************************** 6336 * 6337 * Function; 6338 * Handles the WM_SETREDRAW message. 6339 * 6340 * Documentation: 6341 * According to testing V4.71 of COMCTL32 returns the 6342 * *previous* status of the redraw flag (either 0 or 1) 6343 * instead of the MSDN documented value of 0 if handled. 6344 * (For laughs see the "consistency" with same function 6345 * in rebar.) 6346 * 6347 *****************************************************/ 6348 { 6349 BOOL oldredraw = infoPtr->bDoRedraw; 6350 6351 TRACE("set to %s\n", 6352 (wParam) ? "TRUE" : "FALSE"); 6353 infoPtr->bDoRedraw = (BOOL) wParam; 6354 if (wParam) { 6355 InvalidateRect (infoPtr->hwndSelf, 0, TRUE); 6356 } 6357 return (oldredraw) ? 1 : 0; 6358 } 6359 6360 6361 static LRESULT 6362 TOOLBAR_Size (TOOLBAR_INFO *infoPtr) 6363 { 6364 TRACE("sizing toolbar!\n"); 6365 6366 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) 6367 { 6368 RECT delta_width, delta_height, client, dummy; 6369 DWORD min_x, max_x, min_y, max_y; 6370 TBUTTON_INFO *btnPtr; 6371 INT i; 6372 6373 GetClientRect(infoPtr->hwndSelf, &client); 6374 if(client.right > infoPtr->client_rect.right) 6375 { 6376 min_x = infoPtr->client_rect.right; 6377 max_x = client.right; 6378 } 6379 else 6380 { 6381 max_x = infoPtr->client_rect.right; 6382 min_x = client.right; 6383 } 6384 if(client.bottom > infoPtr->client_rect.bottom) 6385 { 6386 min_y = infoPtr->client_rect.bottom; 6387 max_y = client.bottom; 6388 } 6389 else 6390 { 6391 max_y = infoPtr->client_rect.bottom; 6392 min_y = client.bottom; 6393 } 6394 6395 SetRect(&delta_width, min_x, 0, max_x, min_y); 6396 SetRect(&delta_height, 0, min_y, max_x, max_y); 6397 6398 TRACE("delta_width %s delta_height %s\n", wine_dbgstr_rect(&delta_width), wine_dbgstr_rect(&delta_height)); 6399 btnPtr = infoPtr->buttons; 6400 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) 6401 if(IntersectRect(&dummy, &delta_width, &btnPtr->rect) || 6402 IntersectRect(&dummy, &delta_height, &btnPtr->rect)) 6403 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 6404 } 6405 GetClientRect(infoPtr->hwndSelf, &infoPtr->client_rect); 6406 TOOLBAR_AutoSize(infoPtr); 6407 return 0; 6408 } 6409 6410 6411 static LRESULT 6412 TOOLBAR_StyleChanged (TOOLBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle) 6413 { 6414 if (nType == GWL_STYLE) 6415 { 6416 DWORD dwOldStyle = infoPtr->dwStyle; 6417 6418 if (lpStyle->styleNew & TBSTYLE_LIST) 6419 infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; 6420 else 6421 infoPtr->dwDTFlags = DT_CENTER | DT_END_ELLIPSIS; 6422 6423 TRACE("new style 0x%08x\n", lpStyle->styleNew); 6424 6425 infoPtr->dwStyle = lpStyle->styleNew; 6426 TOOLBAR_CheckStyle (infoPtr); 6427 6428 if ((dwOldStyle ^ lpStyle->styleNew) & (TBSTYLE_WRAPABLE | CCS_VERT)) 6429 TOOLBAR_LayoutToolbar(infoPtr); 6430 6431 /* only resize if one of the CCS_* styles was changed */ 6432 if ((dwOldStyle ^ lpStyle->styleNew) & COMMON_STYLES) 6433 { 6434 TOOLBAR_AutoSize (infoPtr); 6435 6436 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 6437 } 6438 } 6439 6440 return 0; 6441 } 6442 6443 6444 static LRESULT 6445 TOOLBAR_SysColorChange (void) 6446 { 6447 COMCTL32_RefreshSysColors(); 6448 6449 return 0; 6450 } 6451 6452 6453 static LRESULT WINAPI 6454 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 6455 { 6456 TOOLBAR_INFO *infoPtr = (TOOLBAR_INFO *)GetWindowLongPtrW(hwnd, 0); 6457 6458 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", 6459 hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam); 6460 6461 if (!infoPtr && (uMsg != WM_NCCREATE)) 6462 return DefWindowProcW( hwnd, uMsg, wParam, lParam ); 6463 6464 switch (uMsg) 6465 { 6466 case TB_ADDBITMAP: 6467 return TOOLBAR_AddBitmap (infoPtr, (INT)wParam, (TBADDBITMAP*)lParam); 6468 6469 case TB_ADDBUTTONSA: 6470 case TB_ADDBUTTONSW: 6471 return TOOLBAR_AddButtonsT (infoPtr, wParam, (LPTBBUTTON)lParam, 6472 uMsg == TB_ADDBUTTONSW); 6473 case TB_ADDSTRINGA: 6474 return TOOLBAR_AddStringA (infoPtr, (HINSTANCE)wParam, lParam); 6475 6476 case TB_ADDSTRINGW: 6477 return TOOLBAR_AddStringW (infoPtr, (HINSTANCE)wParam, lParam); 6478 6479 case TB_AUTOSIZE: 6480 return TOOLBAR_AutoSize (infoPtr); 6481 6482 case TB_BUTTONCOUNT: 6483 return TOOLBAR_ButtonCount (infoPtr); 6484 6485 case TB_BUTTONSTRUCTSIZE: 6486 return TOOLBAR_ButtonStructSize (infoPtr, wParam); 6487 6488 case TB_CHANGEBITMAP: 6489 return TOOLBAR_ChangeBitmap (infoPtr, wParam, LOWORD(lParam)); 6490 6491 case TB_CHECKBUTTON: 6492 return TOOLBAR_CheckButton (infoPtr, wParam, lParam); 6493 6494 case TB_COMMANDTOINDEX: 6495 return TOOLBAR_CommandToIndex (infoPtr, wParam); 6496 6497 case TB_CUSTOMIZE: 6498 return TOOLBAR_Customize (infoPtr); 6499 6500 case TB_DELETEBUTTON: 6501 return TOOLBAR_DeleteButton (infoPtr, wParam); 6502 6503 case TB_ENABLEBUTTON: 6504 return TOOLBAR_EnableButton (infoPtr, wParam, lParam); 6505 6506 case TB_GETANCHORHIGHLIGHT: 6507 return TOOLBAR_GetAnchorHighlight (infoPtr); 6508 6509 case TB_GETBITMAP: 6510 return TOOLBAR_GetBitmap (infoPtr, wParam); 6511 6512 case TB_GETBITMAPFLAGS: 6513 return TOOLBAR_GetBitmapFlags (); 6514 6515 case TB_GETBUTTON: 6516 return TOOLBAR_GetButton (infoPtr, wParam, (TBBUTTON*)lParam); 6517 6518 case TB_GETBUTTONINFOA: 6519 case TB_GETBUTTONINFOW: 6520 return TOOLBAR_GetButtonInfoT (infoPtr, wParam, (LPTBBUTTONINFOW)lParam, 6521 uMsg == TB_GETBUTTONINFOW); 6522 case TB_GETBUTTONSIZE: 6523 return TOOLBAR_GetButtonSize (infoPtr); 6524 6525 case TB_GETBUTTONTEXTA: 6526 case TB_GETBUTTONTEXTW: 6527 return TOOLBAR_GetButtonText (infoPtr, wParam, (LPWSTR)lParam, 6528 uMsg == TB_GETBUTTONTEXTW); 6529 6530 case TB_GETDISABLEDIMAGELIST: 6531 return TOOLBAR_GetDisabledImageList (infoPtr, wParam); 6532 6533 case TB_GETEXTENDEDSTYLE: 6534 return TOOLBAR_GetExtendedStyle (infoPtr); 6535 6536 case TB_GETHOTIMAGELIST: 6537 return TOOLBAR_GetHotImageList (infoPtr, wParam); 6538 6539 case TB_GETHOTITEM: 6540 return TOOLBAR_GetHotItem (infoPtr); 6541 6542 case TB_GETIMAGELIST: 6543 return TOOLBAR_GetDefImageList (infoPtr, wParam); 6544 6545 case TB_GETINSERTMARK: 6546 return TOOLBAR_GetInsertMark (infoPtr, (TBINSERTMARK*)lParam); 6547 6548 case TB_GETINSERTMARKCOLOR: 6549 return TOOLBAR_GetInsertMarkColor (infoPtr); 6550 6551 case TB_GETITEMRECT: 6552 return TOOLBAR_GetItemRect (infoPtr, wParam, (LPRECT)lParam); 6553 6554 case TB_GETMAXSIZE: 6555 return TOOLBAR_GetMaxSize (infoPtr, (LPSIZE)lParam); 6556 6557 case TB_GETMETRICS: 6558 return TOOLBAR_GetMetrics (infoPtr, (TBMETRICS*)lParam); 6559 6560 /* case TB_GETOBJECT: */ /* 4.71 */ 6561 6562 case TB_GETPADDING: 6563 return TOOLBAR_GetPadding (infoPtr); 6564 6565 case TB_GETRECT: 6566 return TOOLBAR_GetRect (infoPtr, wParam, (LPRECT)lParam); 6567 6568 case TB_GETROWS: 6569 return TOOLBAR_GetRows (infoPtr); 6570 6571 case TB_GETSTATE: 6572 return TOOLBAR_GetState (infoPtr, wParam); 6573 6574 case TB_GETSTRINGA: 6575 return TOOLBAR_GetStringA (infoPtr, wParam, (LPSTR)lParam); 6576 6577 case TB_GETSTRINGW: 6578 return TOOLBAR_GetStringW (infoPtr, wParam, (LPWSTR)lParam); 6579 6580 case TB_GETSTYLE: 6581 return TOOLBAR_GetStyle (infoPtr); 6582 6583 case TB_GETTEXTROWS: 6584 return TOOLBAR_GetTextRows (infoPtr); 6585 6586 case TB_GETTOOLTIPS: 6587 return TOOLBAR_GetToolTips (infoPtr); 6588 6589 case TB_GETUNICODEFORMAT: 6590 return TOOLBAR_GetUnicodeFormat (infoPtr); 6591 6592 case TB_HIDEBUTTON: 6593 return TOOLBAR_HideButton (infoPtr, wParam, LOWORD(lParam)); 6594 6595 case TB_HITTEST: 6596 return TOOLBAR_HitTest (infoPtr, (LPPOINT)lParam); 6597 6598 case TB_INDETERMINATE: 6599 return TOOLBAR_Indeterminate (infoPtr, wParam, LOWORD(lParam)); 6600 6601 case TB_INSERTBUTTONA: 6602 case TB_INSERTBUTTONW: 6603 return TOOLBAR_InsertButtonT(infoPtr, wParam, (TBBUTTON*)lParam, 6604 uMsg == TB_INSERTBUTTONW); 6605 6606 /* case TB_INSERTMARKHITTEST: */ /* 4.71 */ 6607 6608 case TB_ISBUTTONCHECKED: 6609 return TOOLBAR_IsButtonChecked (infoPtr, wParam); 6610 6611 case TB_ISBUTTONENABLED: 6612 return TOOLBAR_IsButtonEnabled (infoPtr, wParam); 6613 6614 case TB_ISBUTTONHIDDEN: 6615 return TOOLBAR_IsButtonHidden (infoPtr, wParam); 6616 6617 case TB_ISBUTTONHIGHLIGHTED: 6618 return TOOLBAR_IsButtonHighlighted (infoPtr, wParam); 6619 6620 case TB_ISBUTTONINDETERMINATE: 6621 return TOOLBAR_IsButtonIndeterminate (infoPtr, wParam); 6622 6623 case TB_ISBUTTONPRESSED: 6624 return TOOLBAR_IsButtonPressed (infoPtr, wParam); 6625 6626 case TB_LOADIMAGES: 6627 return TOOLBAR_LoadImages (infoPtr, wParam, (HINSTANCE)lParam); 6628 6629 case TB_MAPACCELERATORA: 6630 case TB_MAPACCELERATORW: 6631 return TOOLBAR_MapAccelerator (infoPtr, wParam, (UINT*)lParam); 6632 6633 case TB_MARKBUTTON: 6634 return TOOLBAR_MarkButton (infoPtr, wParam, LOWORD(lParam)); 6635 6636 case TB_MOVEBUTTON: 6637 return TOOLBAR_MoveButton (infoPtr, wParam, lParam); 6638 6639 case TB_PRESSBUTTON: 6640 return TOOLBAR_PressButton (infoPtr, wParam, LOWORD(lParam)); 6641 6642 case TB_REPLACEBITMAP: 6643 return TOOLBAR_ReplaceBitmap (infoPtr, (LPTBREPLACEBITMAP)lParam); 6644 6645 case TB_SAVERESTOREA: 6646 return TOOLBAR_SaveRestoreA (infoPtr, wParam, (LPTBSAVEPARAMSA)lParam); 6647 6648 case TB_SAVERESTOREW: 6649 return TOOLBAR_SaveRestoreW (infoPtr, wParam, (LPTBSAVEPARAMSW)lParam); 6650 6651 case TB_SETANCHORHIGHLIGHT: 6652 return TOOLBAR_SetAnchorHighlight (infoPtr, (BOOL)wParam); 6653 6654 case TB_SETBITMAPSIZE: 6655 return TOOLBAR_SetBitmapSize (infoPtr, wParam, lParam); 6656 6657 case TB_SETBUTTONINFOA: 6658 case TB_SETBUTTONINFOW: 6659 return TOOLBAR_SetButtonInfo (infoPtr, wParam, (LPTBBUTTONINFOW)lParam, 6660 uMsg == TB_SETBUTTONINFOW); 6661 case TB_SETBUTTONSIZE: 6662 return TOOLBAR_SetButtonSize (infoPtr, lParam); 6663 6664 case TB_SETBUTTONWIDTH: 6665 return TOOLBAR_SetButtonWidth (infoPtr, lParam); 6666 6667 case TB_SETCMDID: 6668 return TOOLBAR_SetCmdId (infoPtr, wParam, lParam); 6669 6670 case TB_SETDISABLEDIMAGELIST: 6671 return TOOLBAR_SetDisabledImageList (infoPtr, wParam, (HIMAGELIST)lParam); 6672 6673 case TB_SETDRAWTEXTFLAGS: 6674 return TOOLBAR_SetDrawTextFlags (infoPtr, wParam, lParam); 6675 6676 case TB_SETEXTENDEDSTYLE: 6677 return TOOLBAR_SetExtendedStyle (infoPtr, wParam, lParam); 6678 6679 case TB_SETHOTIMAGELIST: 6680 return TOOLBAR_SetHotImageList (infoPtr, wParam, (HIMAGELIST)lParam); 6681 6682 case TB_SETHOTITEM: 6683 return TOOLBAR_SetHotItem (infoPtr, wParam); 6684 6685 case TB_SETIMAGELIST: 6686 return TOOLBAR_SetImageList (infoPtr, wParam, (HIMAGELIST)lParam); 6687 6688 case TB_SETINDENT: 6689 return TOOLBAR_SetIndent (infoPtr, wParam); 6690 6691 case TB_SETINSERTMARK: 6692 return TOOLBAR_SetInsertMark (infoPtr, (TBINSERTMARK*)lParam); 6693 6694 case TB_SETINSERTMARKCOLOR: 6695 return TOOLBAR_SetInsertMarkColor (infoPtr, lParam); 6696 6697 case TB_SETMAXTEXTROWS: 6698 return TOOLBAR_SetMaxTextRows (infoPtr, wParam); 6699 6700 case TB_SETMETRICS: 6701 return TOOLBAR_SetMetrics (infoPtr, (TBMETRICS*)lParam); 6702 6703 case TB_SETPADDING: 6704 return TOOLBAR_SetPadding (infoPtr, lParam); 6705 6706 case TB_SETPARENT: 6707 return TOOLBAR_SetParent (infoPtr, (HWND)wParam); 6708 6709 case TB_SETROWS: 6710 return TOOLBAR_SetRows (infoPtr, wParam, (LPRECT)lParam); 6711 6712 case TB_SETSTATE: 6713 return TOOLBAR_SetState (infoPtr, wParam, lParam); 6714 6715 case TB_SETSTYLE: 6716 return TOOLBAR_SetStyle (infoPtr, lParam); 6717 6718 case TB_SETTOOLTIPS: 6719 return TOOLBAR_SetToolTips (infoPtr, (HWND)wParam); 6720 6721 case TB_SETUNICODEFORMAT: 6722 return TOOLBAR_SetUnicodeFormat (infoPtr, wParam); 6723 6724 case TB_UNKWN45D: 6725 return TOOLBAR_Unkwn45D(hwnd, wParam, lParam); 6726 6727 case TB_SETHOTITEM2: 6728 return TOOLBAR_SetHotItem2 (infoPtr, wParam, lParam); 6729 6730 case TB_SETLISTGAP: 6731 return TOOLBAR_SetListGap(infoPtr, wParam); 6732 6733 case TB_GETIMAGELISTCOUNT: 6734 return TOOLBAR_GetImageListCount(infoPtr); 6735 6736 case TB_GETIDEALSIZE: 6737 return TOOLBAR_GetIdealSize (infoPtr, wParam, lParam); 6738 6739 case TB_UNKWN464: 6740 return TOOLBAR_Unkwn464(hwnd, wParam, lParam); 6741 6742 /* Common Control Messages */ 6743 6744 /* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */ 6745 case CCM_GETCOLORSCHEME: 6746 return TOOLBAR_GetColorScheme (infoPtr, (LPCOLORSCHEME)lParam); 6747 6748 /* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */ 6749 case CCM_SETCOLORSCHEME: 6750 return TOOLBAR_SetColorScheme (infoPtr, (LPCOLORSCHEME)lParam); 6751 6752 case CCM_GETVERSION: 6753 return TOOLBAR_GetVersion (infoPtr); 6754 6755 case CCM_SETVERSION: 6756 return TOOLBAR_SetVersion (infoPtr, (INT)wParam); 6757 6758 6759 /* case WM_CHAR: */ 6760 6761 case WM_CREATE: 6762 return TOOLBAR_Create (hwnd, (CREATESTRUCTW*)lParam); 6763 6764 case WM_DESTROY: 6765 return TOOLBAR_Destroy (infoPtr); 6766 6767 case WM_ERASEBKGND: 6768 return TOOLBAR_EraseBackground (infoPtr, wParam, lParam); 6769 6770 case WM_GETFONT: 6771 return TOOLBAR_GetFont (infoPtr); 6772 6773 case WM_KEYDOWN: 6774 return TOOLBAR_KeyDown (infoPtr, wParam, lParam); 6775 6776 /* case WM_KILLFOCUS: */ 6777 6778 case WM_LBUTTONDBLCLK: 6779 return TOOLBAR_LButtonDblClk (infoPtr, wParam, lParam); 6780 6781 case WM_LBUTTONDOWN: 6782 return TOOLBAR_LButtonDown (infoPtr, wParam, lParam); 6783 6784 case WM_LBUTTONUP: 6785 return TOOLBAR_LButtonUp (infoPtr, wParam, lParam); 6786 6787 case WM_RBUTTONUP: 6788 return TOOLBAR_RButtonUp (infoPtr, wParam, lParam); 6789 6790 case WM_RBUTTONDBLCLK: 6791 return TOOLBAR_RButtonDblClk (infoPtr, wParam, lParam); 6792 6793 case WM_MOUSEMOVE: 6794 return TOOLBAR_MouseMove (infoPtr, wParam, lParam); 6795 6796 case WM_MOUSELEAVE: 6797 return TOOLBAR_MouseLeave (infoPtr); 6798 6799 case WM_CAPTURECHANGED: 6800 return TOOLBAR_CaptureChanged(infoPtr); 6801 6802 case WM_NCACTIVATE: 6803 return TOOLBAR_NCActivate (hwnd, wParam, lParam); 6804 6805 case WM_NCCALCSIZE: 6806 return TOOLBAR_NCCalcSize (hwnd, wParam, lParam); 6807 6808 case WM_NCCREATE: 6809 return TOOLBAR_NCCreate (hwnd, wParam, (CREATESTRUCTW*)lParam); 6810 6811 case WM_NCPAINT: 6812 return TOOLBAR_NCPaint (hwnd, wParam, lParam); 6813 6814 case WM_NOTIFY: 6815 return TOOLBAR_Notify (infoPtr, (LPNMHDR)lParam); 6816 6817 case WM_NOTIFYFORMAT: 6818 return TOOLBAR_NotifyFormat (infoPtr, wParam, lParam); 6819 6820 case WM_PRINTCLIENT: 6821 case WM_PAINT: 6822 return TOOLBAR_Paint (infoPtr, wParam); 6823 6824 case WM_SETFOCUS: 6825 return TOOLBAR_SetFocus (infoPtr); 6826 6827 case WM_SETFONT: 6828 return TOOLBAR_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam); 6829 6830 case WM_SETREDRAW: 6831 return TOOLBAR_SetRedraw (infoPtr, wParam); 6832 6833 case WM_SIZE: 6834 return TOOLBAR_Size (infoPtr); 6835 6836 case WM_STYLECHANGED: 6837 return TOOLBAR_StyleChanged (infoPtr, (INT)wParam, (LPSTYLESTRUCT)lParam); 6838 6839 case WM_SYSCOLORCHANGE: 6840 return TOOLBAR_SysColorChange (); 6841 6842 case WM_THEMECHANGED: 6843 return TOOLBAR_ThemeChanged(hwnd); 6844 6845 /* case WM_WININICHANGE: */ 6846 6847 case WM_CHARTOITEM: 6848 case WM_COMMAND: 6849 case WM_DRAWITEM: 6850 case WM_MEASUREITEM: 6851 case WM_VKEYTOITEM: 6852 return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); 6853 6854 /* We see this in Outlook Express 5.x and just does DefWindowProc */ 6855 case PGM_FORWARDMOUSE: 6856 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 6857 6858 default: 6859 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 6860 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", 6861 uMsg, wParam, lParam); 6862 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 6863 } 6864 } 6865 6866 6867 VOID 6868 TOOLBAR_Register (void) 6869 { 6870 WNDCLASSW wndClass; 6871 6872 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 6873 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; 6874 wndClass.lpfnWndProc = ToolbarWindowProc; 6875 wndClass.cbClsExtra = 0; 6876 wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *); 6877 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 6878 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 6879 wndClass.lpszClassName = TOOLBARCLASSNAMEW; 6880 6881 RegisterClassW (&wndClass); 6882 } 6883 6884 6885 VOID 6886 TOOLBAR_Unregister (void) 6887 { 6888 UnregisterClassW (TOOLBARCLASSNAMEW, NULL); 6889 } 6890 6891 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id) 6892 { 6893 HIMAGELIST himlold; 6894 PIMLENTRY c = NULL; 6895 6896 /* Check if the entry already exists */ 6897 c = TOOLBAR_GetImageListEntry(*pies, *cies, id); 6898 6899 /* If this is a new entry we must create it and insert into the array */ 6900 if (!c) 6901 { 6902 PIMLENTRY *pnies; 6903 6904 c = Alloc(sizeof(IMLENTRY)); 6905 c->id = id; 6906 6907 pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY)); 6908 memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY))); 6909 pnies[*cies] = c; 6910 (*cies)++; 6911 6912 Free(*pies); 6913 *pies = pnies; 6914 } 6915 6916 himlold = c->himl; 6917 c->himl = himl; 6918 6919 return himlold; 6920 } 6921 6922 6923 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies) 6924 { 6925 int i; 6926 6927 for (i = 0; i < *cies; i++) 6928 Free((*pies)[i]); 6929 6930 Free(*pies); 6931 6932 *cies = 0; 6933 *pies = NULL; 6934 } 6935 6936 6937 static PIMLENTRY TOOLBAR_GetImageListEntry(const PIMLENTRY *pies, INT cies, INT id) 6938 { 6939 PIMLENTRY c = NULL; 6940 6941 if (pies != NULL) 6942 { 6943 int i; 6944 6945 for (i = 0; i < cies; i++) 6946 { 6947 if (pies[i]->id == id) 6948 { 6949 c = pies[i]; 6950 break; 6951 } 6952 } 6953 } 6954 6955 return c; 6956 } 6957 6958 6959 static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id) 6960 { 6961 HIMAGELIST himlDef = 0; 6962 PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id); 6963 6964 if (pie) 6965 himlDef = pie->himl; 6966 6967 return himlDef; 6968 } 6969 6970 6971 static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb) 6972 { 6973 if (infoPtr->bUnicode) 6974 return TOOLBAR_SendNotify(&nmtb->hdr, infoPtr, TBN_GETBUTTONINFOW); 6975 else 6976 { 6977 CHAR Buffer[256]; 6978 NMTOOLBARA nmtba; 6979 BOOL bRet = FALSE; 6980 6981 nmtba.iItem = nmtb->iItem; 6982 nmtba.pszText = Buffer; 6983 nmtba.cchText = 256; 6984 ZeroMemory(nmtba.pszText, nmtba.cchText); 6985 6986 if (TOOLBAR_SendNotify(&nmtba.hdr, infoPtr, TBN_GETBUTTONINFOA)) 6987 { 6988 int ccht = strlen(nmtba.pszText); 6989 if (ccht) 6990 MultiByteToWideChar(CP_ACP, 0, nmtba.pszText, -1, 6991 nmtb->pszText, nmtb->cchText); 6992 6993 nmtb->tbButton = nmtba.tbButton; 6994 bRet = TRUE; 6995 } 6996 6997 return bRet; 6998 } 6999 } 7000 7001 7002 static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, const CUSTOMBUTTON *btnInfo) 7003 { 7004 NMTOOLBARW nmtb; 7005 7006 /* MSDN states that iItem is the index of the button, rather than the 7007 * command ID as used by every other NMTOOLBAR notification */ 7008 nmtb.iItem = iItem; 7009 memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON)); 7010 7011 return TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYDELETE); 7012 } 7013