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