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