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