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