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