Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygentoolbar.c
Go to the documentation of this file.
00001 /* 00002 * Toolbar control 00003 * 00004 * Copyright 1998,1999 Eric Kohl 00005 * Copyright 2000 Eric Kohl for CodeWeavers 00006 * Copyright 2004 Robert Shearman 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00021 * 00022 * NOTES 00023 * 00024 * This code was audited for completeness against the documented features 00025 * of Comctl32.dll version 6.0 on Mar. 14, 2004, by Robert Shearman. 00026 * 00027 * Unless otherwise noted, we believe this code to be complete, as per 00028 * the specification mentioned above. 00029 * If you discover missing features or bugs please note them below. 00030 * 00031 * TODO: 00032 * - Styles: 00033 * - TBSTYLE_REGISTERDROP 00034 * - TBSTYLE_EX_DOUBLEBUFFER 00035 * - Messages: 00036 * - TB_GETMETRICS 00037 * - TB_GETOBJECT 00038 * - TB_INSERTMARKHITTEST 00039 * - TB_SAVERESTORE 00040 * - TB_SETMETRICS 00041 * - WM_WININICHANGE 00042 * - Notifications: 00043 * - NM_CHAR 00044 * - TBN_GETOBJECT 00045 * - TBN_SAVE 00046 * - Button wrapping (under construction). 00047 * - Fix TB_SETROWS and Separators. 00048 * - iListGap custom draw support. 00049 * 00050 * Testing: 00051 * - Run tests using Waite Group Windows95 API Bible Volume 2. 00052 * The second cdrom contains executables addstr.exe, btncount.exe, 00053 * btnstate.exe, butstrsz.exe, chkbtn.exe, chngbmp.exe, customiz.exe, 00054 * enablebtn.exe, getbmp.exe, getbtn.exe, getflags.exe, hidebtn.exe, 00055 * indetbtn.exe, insbtn.exe, pressbtn.exe, setbtnsz.exe, setcmdid.exe, 00056 * setparnt.exe, setrows.exe, toolwnd.exe. 00057 * - Microsoft's controlspy examples. 00058 * - Charles Petzold's 'Programming Windows': gadgets.exe 00059 * 00060 * Differences between MSDN and actual native control operation: 00061 * 1. MSDN says: "TBSTYLE_LIST: Creates a flat toolbar with button text 00062 * to the right of the bitmap. Otherwise, this style is 00063 * identical to TBSTYLE_FLAT." 00064 * As implemented by both v4.71 and v5.80 of the native COMCTL32.DLL 00065 * you can create a TBSTYLE_LIST without TBSTYLE_FLAT and the result 00066 * is non-flat non-transparent buttons. Therefore TBSTYLE_LIST does 00067 * *not* imply TBSTYLE_FLAT as documented. (GA 8/2001) 00068 * 00069 */ 00070 00071 #include <stdarg.h> 00072 #include <string.h> 00073 00074 #include "windef.h" 00075 #include "winbase.h" 00076 #include "winreg.h" 00077 #include "wingdi.h" 00078 #include "winuser.h" 00079 #include "wine/unicode.h" 00080 #include "winnls.h" 00081 #include "commctrl.h" 00082 #include "comctl32.h" 00083 #include "uxtheme.h" 00084 #include "vssym32.h" 00085 #include "wine/debug.h" 00086 00087 WINE_DEFAULT_DEBUG_CHANNEL(toolbar); 00088 00089 static HCURSOR hCursorDrag = NULL; 00090 00091 typedef struct 00092 { 00093 INT iBitmap; 00094 INT idCommand; 00095 BYTE fsState; 00096 BYTE fsStyle; 00097 BYTE bHot; 00098 BYTE bDropDownPressed; 00099 DWORD_PTR dwData; 00100 INT_PTR iString; 00101 INT nRow; 00102 RECT rect; 00103 INT cx; /* manually set size */ 00104 } TBUTTON_INFO; 00105 00106 typedef struct 00107 { 00108 UINT nButtons; 00109 HINSTANCE hInst; 00110 UINT nID; 00111 } TBITMAP_INFO; 00112 00113 typedef struct 00114 { 00115 HIMAGELIST himl; 00116 INT id; 00117 } IMLENTRY, *PIMLENTRY; 00118 00119 typedef struct 00120 { 00121 DWORD dwStructSize; /* size of TBBUTTON struct */ 00122 INT nWidth; /* width of the toolbar */ 00123 RECT client_rect; 00124 RECT rcBound; /* bounding rectangle */ 00125 INT nButtonHeight; 00126 INT nButtonWidth; 00127 INT nBitmapHeight; 00128 INT nBitmapWidth; 00129 INT nIndent; 00130 INT nRows; /* number of button rows */ 00131 INT nMaxTextRows; /* maximum number of text rows */ 00132 INT cxMin; /* minimum button width */ 00133 INT cxMax; /* maximum button width */ 00134 INT nNumButtons; /* number of buttons */ 00135 INT nNumBitmaps; /* number of bitmaps */ 00136 INT nNumStrings; /* number of strings */ 00137 INT nNumBitmapInfos; 00138 INT nButtonDown; /* toolbar button being pressed or -1 if none */ 00139 INT nButtonDrag; /* toolbar button being dragged or -1 if none */ 00140 INT nOldHit; 00141 INT nHotItem; /* index of the "hot" item */ 00142 SIZE szPadding; /* padding values around button */ 00143 INT iTopMargin; /* the top margin */ 00144 INT iListGap; /* default gap between text and image for toolbar with list style */ 00145 HFONT hDefaultFont; 00146 HFONT hFont; /* text font */ 00147 HIMAGELIST himlInt; /* image list created internally */ 00148 PIMLENTRY *himlDef; /* default image list array */ 00149 INT cimlDef; /* default image list array count */ 00150 PIMLENTRY *himlHot; /* hot image list array */ 00151 INT cimlHot; /* hot image list array count */ 00152 PIMLENTRY *himlDis; /* disabled image list array */ 00153 INT cimlDis; /* disabled image list array count */ 00154 HWND hwndToolTip; /* handle to tool tip control */ 00155 HWND hwndNotify; /* handle to the window that gets notifications */ 00156 HWND hwndSelf; /* my own handle */ 00157 BOOL bAnchor; /* anchor highlight enabled */ 00158 BOOL bDoRedraw; /* Redraw status */ 00159 BOOL bDragOutSent; /* has TBN_DRAGOUT notification been sent for this drag? */ 00160 BOOL bUnicode; /* Notifications are ASCII (FALSE) or Unicode (TRUE)? */ 00161 BOOL bCaptured; /* mouse captured? */ 00162 DWORD dwStyle; /* regular toolbar style */ 00163 DWORD dwExStyle; /* extended toolbar style */ 00164 DWORD dwDTFlags; /* DrawText flags */ 00165 00166 COLORREF clrInsertMark; /* insert mark color */ 00167 COLORREF clrBtnHighlight; /* color for Flat Separator */ 00168 COLORREF clrBtnShadow; /* color for Flag Separator */ 00169 INT iVersion; 00170 LPWSTR pszTooltipText; /* temporary store for a string > 80 characters 00171 * for TTN_GETDISPINFOW notification */ 00172 TBINSERTMARK tbim; /* info on insertion mark */ 00173 TBUTTON_INFO *buttons; /* pointer to button array */ 00174 LPWSTR *strings; /* pointer to string array */ 00175 TBITMAP_INFO *bitmaps; 00176 } TOOLBAR_INFO, *PTOOLBAR_INFO; 00177 00178 00179 /* used by customization dialog */ 00180 typedef struct 00181 { 00182 PTOOLBAR_INFO tbInfo; 00183 HWND tbHwnd; 00184 } CUSTDLG_INFO, *PCUSTDLG_INFO; 00185 00186 typedef struct 00187 { 00188 TBBUTTON btn; 00189 BOOL bVirtual; 00190 BOOL bRemovable; 00191 WCHAR text[64]; 00192 } CUSTOMBUTTON, *PCUSTOMBUTTON; 00193 00194 typedef enum 00195 { 00196 IMAGE_LIST_DEFAULT, 00197 IMAGE_LIST_HOT, 00198 IMAGE_LIST_DISABLED 00199 } IMAGE_LIST_TYPE; 00200 00201 #define SEPARATOR_WIDTH 8 00202 #define TOP_BORDER 2 00203 #define BOTTOM_BORDER 2 00204 #define DDARROW_WIDTH 11 00205 #define ARROW_HEIGHT 3 00206 #define INSERTMARK_WIDTH 2 00207 00208 #define DEFPAD_CX 7 00209 #define DEFPAD_CY 6 00210 #define DEFLISTGAP 4 00211 00212 /* vertical padding used in list mode when image is present */ 00213 #define LISTPAD_CY 9 00214 00215 /* how wide to treat the bitmap if it isn't present */ 00216 #define NONLIST_NOTEXT_OFFSET 2 00217 00218 #define TOOLBAR_NOWHERE (-1) 00219 00220 #define TOOLBAR_HasText(x, y) (TOOLBAR_GetText(x, y) ? TRUE : FALSE) 00221 #define TOOLBAR_HasDropDownArrows(exStyle) ((exStyle & TBSTYLE_EX_DRAWDDARROWS) ? TRUE : FALSE) 00222 00223 /* Used to find undocumented extended styles */ 00224 #define TBSTYLE_EX_ALL (TBSTYLE_EX_DRAWDDARROWS | \ 00225 TBSTYLE_EX_UNDOC1 | \ 00226 TBSTYLE_EX_MIXEDBUTTONS | \ 00227 TBSTYLE_EX_DOUBLEBUFFER | \ 00228 TBSTYLE_EX_HIDECLIPPEDBUTTONS) 00229 00230 /* all of the CCS_ styles */ 00231 #define COMMON_STYLES (CCS_TOP|CCS_NOMOVEY|CCS_BOTTOM|CCS_NORESIZE| \ 00232 CCS_NOPARENTALIGN|CCS_ADJUSTABLE|CCS_NODIVIDER|CCS_VERT) 00233 00234 #define GETIBITMAP(infoPtr, i) (infoPtr->iVersion >= 5 ? LOWORD(i) : i) 00235 #define GETHIMLID(infoPtr, i) (infoPtr->iVersion >= 5 ? HIWORD(i) : 0) 00236 #define GETDEFIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDef, infoPtr->cimlDef, id) 00237 #define GETHOTIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlHot, infoPtr->cimlHot, id) 00238 #define GETDISIMAGELIST(infoPtr, id) TOOLBAR_GetImageList(infoPtr->himlDis, infoPtr->cimlDis, id) 00239 00240 static const WCHAR themeClass[] = { 'T','o','o','l','b','a','r',0 }; 00241 00242 static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb); 00243 static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, const CUSTOMBUTTON *btnInfo); 00244 static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id); 00245 static PIMLENTRY TOOLBAR_GetImageListEntry(const PIMLENTRY *pies, INT cies, INT id); 00246 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies); 00247 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id); 00248 static LRESULT TOOLBAR_LButtonDown(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam); 00249 static void TOOLBAR_LayoutToolbar(TOOLBAR_INFO *infoPtr); 00250 static LRESULT TOOLBAR_AutoSize(TOOLBAR_INFO *infoPtr); 00251 static void TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr); 00252 static void TOOLBAR_TooltipAddTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button); 00253 static void TOOLBAR_TooltipSetRect(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button); 00254 00255 00256 static inline int default_top_margin(const TOOLBAR_INFO *infoPtr) 00257 { 00258 return (infoPtr->dwStyle & TBSTYLE_FLAT ? 0 : TOP_BORDER); 00259 } 00260 00261 static LPWSTR 00262 TOOLBAR_GetText(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *btnPtr) 00263 { 00264 LPWSTR lpText = NULL; 00265 00266 /* NOTE: iString == -1 is undocumented */ 00267 if (!IS_INTRESOURCE(btnPtr->iString) && (btnPtr->iString != -1)) 00268 lpText = (LPWSTR)btnPtr->iString; 00269 else if ((btnPtr->iString >= 0) && (btnPtr->iString < infoPtr->nNumStrings)) 00270 lpText = infoPtr->strings[btnPtr->iString]; 00271 00272 return lpText; 00273 } 00274 00275 static void 00276 TOOLBAR_DumpTBButton(const TBBUTTON *tbb, BOOL fUnicode) 00277 { 00278 TRACE("TBBUTTON: id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08lx (%s)\n", 00279 tbb->idCommand,tbb->iBitmap, tbb->fsState, tbb->fsStyle, tbb->dwData, tbb->iString, 00280 (fUnicode ? wine_dbgstr_w((LPWSTR)tbb->iString) : wine_dbgstr_a((LPSTR)tbb->iString))); 00281 } 00282 00283 static void 00284 TOOLBAR_DumpButton(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *bP, INT btn_num) 00285 { 00286 if (TRACE_ON(toolbar)){ 00287 TRACE("button %d id %d, bitmap=%d, state=%02x, style=%02x, data=%08lx, stringid=0x%08lx\n", 00288 btn_num, bP->idCommand, GETIBITMAP(infoPtr, bP->iBitmap), 00289 bP->fsState, bP->fsStyle, bP->dwData, bP->iString); 00290 TRACE("string %s\n", debugstr_w(TOOLBAR_GetText(infoPtr,bP))); 00291 TRACE("button %d id %d, hot=%s, row=%d, rect=(%s)\n", 00292 btn_num, bP->idCommand, (bP->bHot) ? "TRUE":"FALSE", bP->nRow, 00293 wine_dbgstr_rect(&bP->rect)); 00294 } 00295 } 00296 00297 00298 static void 00299 TOOLBAR_DumpToolbar(const TOOLBAR_INFO *iP, INT line) 00300 { 00301 if (TRACE_ON(toolbar)) { 00302 INT i; 00303 00304 TRACE("toolbar %p at line %d, exStyle=%08x, buttons=%d, bitmaps=%d, strings=%d, style=%08x\n", 00305 iP->hwndSelf, line, 00306 iP->dwExStyle, iP->nNumButtons, iP->nNumBitmaps, 00307 iP->nNumStrings, iP->dwStyle); 00308 TRACE("toolbar %p at line %d, himlInt=%p, himlDef=%p, himlHot=%p, himlDis=%p, redrawable=%s\n", 00309 iP->hwndSelf, line, 00310 iP->himlInt, iP->himlDef, iP->himlHot, iP->himlDis, 00311 (iP->bDoRedraw) ? "TRUE" : "FALSE"); 00312 for(i=0; i<iP->nNumButtons; i++) { 00313 TOOLBAR_DumpButton(iP, &iP->buttons[i], i); 00314 } 00315 } 00316 } 00317 00318 static inline BOOL 00319 TOOLBAR_ButtonHasString(const TBUTTON_INFO *btnPtr) 00320 { 00321 return HIWORD(btnPtr->iString) && btnPtr->iString != -1; 00322 } 00323 00324 /*********************************************************************** 00325 * TOOLBAR_CheckStyle 00326 * 00327 * This function validates that the styles set are implemented and 00328 * issues FIXMEs warning of possible problems. In a perfect world this 00329 * function should be null. 00330 */ 00331 static void 00332 TOOLBAR_CheckStyle (const TOOLBAR_INFO *infoPtr) 00333 { 00334 if (infoPtr->dwStyle & TBSTYLE_REGISTERDROP) 00335 FIXME("[%p] TBSTYLE_REGISTERDROP not implemented\n", infoPtr->hwndSelf); 00336 } 00337 00338 00339 static INT 00340 TOOLBAR_SendNotify (NMHDR *nmhdr, const TOOLBAR_INFO *infoPtr, UINT code) 00341 { 00342 if(!IsWindow(infoPtr->hwndSelf)) 00343 return 0; /* we have just been destroyed */ 00344 00345 nmhdr->idFrom = GetDlgCtrlID (infoPtr->hwndSelf); 00346 nmhdr->hwndFrom = infoPtr->hwndSelf; 00347 nmhdr->code = code; 00348 00349 TRACE("to window %p, code=%08x, %s\n", infoPtr->hwndNotify, code, 00350 (infoPtr->bUnicode) ? "via Unicode" : "via ANSI"); 00351 00352 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, nmhdr->idFrom, (LPARAM)nmhdr); 00353 } 00354 00355 /*********************************************************************** 00356 * TOOLBAR_GetBitmapIndex 00357 * 00358 * This function returns the bitmap index associated with a button. 00359 * If the button specifies I_IMAGECALLBACK, then the TBN_GETDISPINFO 00360 * is issued to retrieve the index. 00361 */ 00362 static INT 00363 TOOLBAR_GetBitmapIndex(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr) 00364 { 00365 INT ret = btnPtr->iBitmap; 00366 00367 if (ret == I_IMAGECALLBACK) 00368 { 00369 /* issue TBN_GETDISPINFO */ 00370 NMTBDISPINFOW nmgd; 00371 00372 memset(&nmgd, 0, sizeof(nmgd)); 00373 nmgd.idCommand = btnPtr->idCommand; 00374 nmgd.lParam = btnPtr->dwData; 00375 nmgd.dwMask = TBNF_IMAGE; 00376 nmgd.iImage = -1; 00377 /* Windows also send TBN_GETDISPINFOW even if the control is ANSI */ 00378 TOOLBAR_SendNotify(&nmgd.hdr, infoPtr, TBN_GETDISPINFOW); 00379 if (nmgd.dwMask & TBNF_DI_SETITEM) 00380 btnPtr->iBitmap = nmgd.iImage; 00381 ret = nmgd.iImage; 00382 TRACE("TBN_GETDISPINFO returned bitmap id %d, mask=%08x, nNumBitmaps=%d\n", 00383 ret, nmgd.dwMask, infoPtr->nNumBitmaps); 00384 } 00385 00386 if (ret != I_IMAGENONE) 00387 ret = GETIBITMAP(infoPtr, ret); 00388 00389 return ret; 00390 } 00391 00392 00393 static BOOL 00394 TOOLBAR_IsValidBitmapIndex(const TOOLBAR_INFO *infoPtr, INT index) 00395 { 00396 HIMAGELIST himl; 00397 INT id = GETHIMLID(infoPtr, index); 00398 INT iBitmap = GETIBITMAP(infoPtr, index); 00399 00400 if (((himl = GETDEFIMAGELIST(infoPtr, id)) && 00401 iBitmap >= 0 && iBitmap < ImageList_GetImageCount(himl)) || 00402 (index == I_IMAGECALLBACK)) 00403 return TRUE; 00404 else 00405 return FALSE; 00406 } 00407 00408 00409 static inline BOOL 00410 TOOLBAR_IsValidImageList(const TOOLBAR_INFO *infoPtr, INT index) 00411 { 00412 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, index)); 00413 return (himl != NULL) && (ImageList_GetImageCount(himl) > 0); 00414 } 00415 00416 00417 /*********************************************************************** 00418 * TOOLBAR_GetImageListForDrawing 00419 * 00420 * This function validates the bitmap index (including I_IMAGECALLBACK 00421 * functionality) and returns the corresponding image list. 00422 */ 00423 static HIMAGELIST 00424 TOOLBAR_GetImageListForDrawing (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, 00425 IMAGE_LIST_TYPE imagelist, INT * index) 00426 { 00427 HIMAGELIST himl; 00428 00429 if (!TOOLBAR_IsValidBitmapIndex(infoPtr,btnPtr->iBitmap)) { 00430 if (btnPtr->iBitmap == I_IMAGENONE) return NULL; 00431 ERR("bitmap for ID %d, index %d is not valid, number of bitmaps in imagelist: %d\n", 00432 HIWORD(btnPtr->iBitmap), LOWORD(btnPtr->iBitmap), infoPtr->nNumBitmaps); 00433 return NULL; 00434 } 00435 00436 if ((*index = TOOLBAR_GetBitmapIndex(infoPtr, btnPtr)) < 0) { 00437 if ((*index == I_IMAGECALLBACK) || 00438 (*index == I_IMAGENONE)) return NULL; 00439 ERR("TBN_GETDISPINFO returned invalid index %d\n", 00440 *index); 00441 return NULL; 00442 } 00443 00444 switch(imagelist) 00445 { 00446 case IMAGE_LIST_DEFAULT: 00447 himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 00448 break; 00449 case IMAGE_LIST_HOT: 00450 himl = GETHOTIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 00451 break; 00452 case IMAGE_LIST_DISABLED: 00453 himl = GETDISIMAGELIST(infoPtr, GETHIMLID(infoPtr, btnPtr->iBitmap)); 00454 break; 00455 default: 00456 himl = NULL; 00457 FIXME("Shouldn't reach here\n"); 00458 } 00459 00460 if (!himl) 00461 TRACE("no image list\n"); 00462 00463 return himl; 00464 } 00465 00466 00467 static void 00468 TOOLBAR_DrawFlatSeparator (const RECT *lpRect, HDC hdc, const TOOLBAR_INFO *infoPtr) 00469 { 00470 RECT myrect; 00471 COLORREF oldcolor, newcolor; 00472 00473 myrect.left = (lpRect->left + lpRect->right) / 2 - 1; 00474 myrect.right = myrect.left + 1; 00475 myrect.top = lpRect->top + 2; 00476 myrect.bottom = lpRect->bottom - 2; 00477 00478 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 00479 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 00480 oldcolor = SetBkColor (hdc, newcolor); 00481 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 00482 00483 myrect.left = myrect.right; 00484 myrect.right = myrect.left + 1; 00485 00486 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 00487 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; 00488 SetBkColor (hdc, newcolor); 00489 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 00490 00491 SetBkColor (hdc, oldcolor); 00492 } 00493 00494 00495 /*********************************************************************** 00496 * TOOLBAR_DrawFlatHorizontalSeparator 00497 * 00498 * This function draws horizontal separator for toolbars having CCS_VERT style. 00499 * In this case, the separator is a pixel high line of COLOR_BTNSHADOW, 00500 * followed by a pixel high line of COLOR_BTNHIGHLIGHT. These separators 00501 * are horizontal as opposed to the vertical separators for not dropdown 00502 * type. 00503 * 00504 * FIXME: It is possible that the height of each line is really SM_CYBORDER. 00505 */ 00506 static void 00507 TOOLBAR_DrawFlatHorizontalSeparator (const RECT *lpRect, HDC hdc, 00508 const TOOLBAR_INFO *infoPtr) 00509 { 00510 RECT myrect; 00511 COLORREF oldcolor, newcolor; 00512 00513 myrect.left = lpRect->left; 00514 myrect.right = lpRect->right; 00515 myrect.top = lpRect->top + (lpRect->bottom - lpRect->top - 2)/2; 00516 myrect.bottom = myrect.top + 1; 00517 00518 InflateRect (&myrect, -2, 0); 00519 00520 TRACE("rect=(%s)\n", wine_dbgstr_rect(&myrect)); 00521 00522 newcolor = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 00523 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 00524 oldcolor = SetBkColor (hdc, newcolor); 00525 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 00526 00527 myrect.top = myrect.bottom; 00528 myrect.bottom = myrect.top + 1; 00529 00530 newcolor = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 00531 comctl32_color.clrBtnHighlight : infoPtr->clrBtnHighlight; 00532 SetBkColor (hdc, newcolor); 00533 ExtTextOutW (hdc, 0, 0, ETO_OPAQUE, &myrect, 0, 0, 0); 00534 00535 SetBkColor (hdc, oldcolor); 00536 } 00537 00538 00539 static void 00540 TOOLBAR_DrawArrow (HDC hdc, INT left, INT top, COLORREF clr) 00541 { 00542 INT x, y; 00543 HPEN hPen, hOldPen; 00544 00545 if (!(hPen = CreatePen( PS_SOLID, 1, clr))) return; 00546 hOldPen = SelectObject ( hdc, hPen ); 00547 x = left + 2; 00548 y = top; 00549 MoveToEx (hdc, x, y, NULL); 00550 LineTo (hdc, x+5, y++); x++; 00551 MoveToEx (hdc, x, y, NULL); 00552 LineTo (hdc, x+3, y++); x++; 00553 MoveToEx (hdc, x, y, NULL); 00554 LineTo (hdc, x+1, y); 00555 SelectObject( hdc, hOldPen ); 00556 DeleteObject( hPen ); 00557 } 00558 00559 /* 00560 * Draw the text string for this button. 00561 * note: infoPtr->himlDis *SHOULD* be non-zero when infoPtr->himlDef 00562 * is non-zero, so we can simply check himlDef to see if we have 00563 * an image list 00564 */ 00565 static void 00566 TOOLBAR_DrawString (const TOOLBAR_INFO *infoPtr, RECT *rcText, LPCWSTR lpText, 00567 const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) 00568 { 00569 HDC hdc = tbcd->nmcd.hdc; 00570 HFONT hOldFont = 0; 00571 COLORREF clrOld = 0; 00572 COLORREF clrOldBk = 0; 00573 int oldBkMode = 0; 00574 UINT state = tbcd->nmcd.uItemState; 00575 00576 /* draw text */ 00577 if (lpText && infoPtr->nMaxTextRows > 0) { 00578 TRACE("string=%s rect=(%s)\n", debugstr_w(lpText), 00579 wine_dbgstr_rect(rcText)); 00580 00581 hOldFont = SelectObject (hdc, infoPtr->hFont); 00582 if ((state & CDIS_HOT) && (dwItemCDFlag & TBCDRF_HILITEHOTTRACK )) { 00583 clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); 00584 } 00585 else if (state & CDIS_DISABLED) { 00586 clrOld = SetTextColor (hdc, tbcd->clrBtnHighlight); 00587 OffsetRect (rcText, 1, 1); 00588 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); 00589 SetTextColor (hdc, comctl32_color.clr3dShadow); 00590 OffsetRect (rcText, -1, -1); 00591 } 00592 else if (state & CDIS_INDETERMINATE) { 00593 clrOld = SetTextColor (hdc, comctl32_color.clr3dShadow); 00594 } 00595 else if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK)) { 00596 clrOld = SetTextColor (hdc, tbcd->clrTextHighlight); 00597 clrOldBk = SetBkColor (hdc, tbcd->clrMark); 00598 oldBkMode = SetBkMode (hdc, tbcd->nHLStringBkMode); 00599 } 00600 else { 00601 clrOld = SetTextColor (hdc, tbcd->clrText); 00602 } 00603 00604 DrawTextW (hdc, lpText, -1, rcText, infoPtr->dwDTFlags); 00605 SetTextColor (hdc, clrOld); 00606 if ((state & CDIS_MARKED) && !(dwItemCDFlag & TBCDRF_NOMARK)) 00607 { 00608 SetBkColor (hdc, clrOldBk); 00609 SetBkMode (hdc, oldBkMode); 00610 } 00611 SelectObject (hdc, hOldFont); 00612 } 00613 } 00614 00615 00616 static void 00617 TOOLBAR_DrawPattern (const RECT *lpRect, const NMTBCUSTOMDRAW *tbcd) 00618 { 00619 HDC hdc = tbcd->nmcd.hdc; 00620 HBRUSH hbr = SelectObject (hdc, tbcd->hbrMonoDither); 00621 COLORREF clrTextOld; 00622 COLORREF clrBkOld; 00623 INT cx = lpRect->right - lpRect->left; 00624 INT cy = lpRect->bottom - lpRect->top; 00625 INT cxEdge = GetSystemMetrics(SM_CXEDGE); 00626 INT cyEdge = GetSystemMetrics(SM_CYEDGE); 00627 clrTextOld = SetTextColor(hdc, tbcd->clrBtnHighlight); 00628 clrBkOld = SetBkColor(hdc, tbcd->clrBtnFace); 00629 PatBlt (hdc, lpRect->left + cxEdge, lpRect->top + cyEdge, 00630 cx - (2 * cxEdge), cy - (2 * cyEdge), PATCOPY); 00631 SetBkColor(hdc, clrBkOld); 00632 SetTextColor(hdc, clrTextOld); 00633 SelectObject (hdc, hbr); 00634 } 00635 00636 00637 static void TOOLBAR_DrawMasked(HIMAGELIST himl, int index, HDC hdc, INT x, INT y, UINT draw_flags) 00638 { 00639 INT cx, cy; 00640 HBITMAP hbmMask, hbmImage; 00641 HDC hdcMask, hdcImage; 00642 00643 ImageList_GetIconSize(himl, &cx, &cy); 00644 00645 /* Create src image */ 00646 hdcImage = CreateCompatibleDC(hdc); 00647 hbmImage = CreateCompatibleBitmap(hdc, cx, cy); 00648 SelectObject(hdcImage, hbmImage); 00649 ImageList_DrawEx(himl, index, hdcImage, 0, 0, cx, cy, 00650 RGB(0xff, 0xff, 0xff), RGB(0,0,0), draw_flags); 00651 00652 /* Create Mask */ 00653 hdcMask = CreateCompatibleDC(0); 00654 hbmMask = CreateBitmap(cx, cy, 1, 1, NULL); 00655 SelectObject(hdcMask, hbmMask); 00656 00657 /* Remove the background and all white pixels */ 00658 ImageList_DrawEx(himl, index, hdcMask, 0, 0, cx, cy, 00659 RGB(0xff, 0xff, 0xff), RGB(0,0,0), ILD_MASK); 00660 SetBkColor(hdcImage, RGB(0xff, 0xff, 0xff)); 00661 BitBlt(hdcMask, 0, 0, cx, cy, hdcImage, 0, 0, NOTSRCERASE); 00662 00663 /* draw the new mask 'etched' to hdc */ 00664 SetBkColor(hdc, RGB(255, 255, 255)); 00665 SelectObject(hdc, GetSysColorBrush(COLOR_3DHILIGHT)); 00666 /* E20746 op code is (Dst ^ (Src & (Pat ^ Dst))) */ 00667 BitBlt(hdc, x + 1, y + 1, cx, cy, hdcMask, 0, 0, 0xE20746); 00668 SelectObject(hdc, GetSysColorBrush(COLOR_3DSHADOW)); 00669 BitBlt(hdc, x, y, cx, cy, hdcMask, 0, 0, 0xE20746); 00670 00671 /* Cleanup */ 00672 DeleteObject(hbmImage); 00673 DeleteDC(hdcImage); 00674 DeleteObject (hbmMask); 00675 DeleteDC(hdcMask); 00676 } 00677 00678 00679 static UINT 00680 TOOLBAR_TranslateState(const TBUTTON_INFO *btnPtr) 00681 { 00682 UINT retstate = 0; 00683 00684 retstate |= (btnPtr->fsState & TBSTATE_CHECKED) ? CDIS_CHECKED : 0; 00685 retstate |= (btnPtr->fsState & TBSTATE_PRESSED) ? CDIS_SELECTED : 0; 00686 retstate |= (btnPtr->fsState & TBSTATE_ENABLED) ? 0 : CDIS_DISABLED; 00687 retstate |= (btnPtr->fsState & TBSTATE_MARKED ) ? CDIS_MARKED : 0; 00688 retstate |= (btnPtr->bHot ) ? CDIS_HOT : 0; 00689 retstate |= ((btnPtr->fsState & (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) == (TBSTATE_ENABLED|TBSTATE_INDETERMINATE)) ? CDIS_INDETERMINATE : 0; 00690 /* NOTE: we don't set CDIS_GRAYED, CDIS_FOCUS, CDIS_DEFAULT */ 00691 return retstate; 00692 } 00693 00694 /* draws the image on a toolbar button */ 00695 static void 00696 TOOLBAR_DrawImage(const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, INT left, INT top, 00697 const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) 00698 { 00699 HIMAGELIST himl = NULL; 00700 BOOL draw_masked = FALSE; 00701 INT index; 00702 INT offset = 0; 00703 UINT draw_flags = ILD_TRANSPARENT; 00704 00705 if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 00706 { 00707 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DISABLED, &index); 00708 if (!himl) 00709 { 00710 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 00711 draw_masked = TRUE; 00712 } 00713 } 00714 else if (tbcd->nmcd.uItemState & CDIS_CHECKED || 00715 ((tbcd->nmcd.uItemState & CDIS_HOT) 00716 && ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)))) 00717 { 00718 /* if hot, attempt to draw with hot image list, if fails, 00719 use default image list */ 00720 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_HOT, &index); 00721 if (!himl) 00722 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 00723 } 00724 else 00725 himl = TOOLBAR_GetImageListForDrawing(infoPtr, btnPtr, IMAGE_LIST_DEFAULT, &index); 00726 00727 if (!himl) 00728 return; 00729 00730 if (!(dwItemCDFlag & TBCDRF_NOOFFSET) && 00731 (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED))) 00732 offset = 1; 00733 00734 if (!(dwItemCDFlag & TBCDRF_NOMARK) && 00735 (tbcd->nmcd.uItemState & CDIS_MARKED)) 00736 draw_flags |= ILD_BLEND50; 00737 00738 TRACE("drawing index=%d, himl=%p, left=%d, top=%d, offset=%d\n", 00739 index, himl, left, top, offset); 00740 00741 if (draw_masked) 00742 TOOLBAR_DrawMasked (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); 00743 else 00744 ImageList_Draw (himl, index, tbcd->nmcd.hdc, left + offset, top + offset, draw_flags); 00745 } 00746 00747 /* draws a blank frame for a toolbar button */ 00748 static void 00749 TOOLBAR_DrawFrame(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, DWORD dwItemCDFlag) 00750 { 00751 HDC hdc = tbcd->nmcd.hdc; 00752 RECT rc = tbcd->nmcd.rc; 00753 /* if the state is disabled or indeterminate then the button 00754 * cannot have an interactive look like pressed or hot */ 00755 BOOL non_interactive_state = (tbcd->nmcd.uItemState & CDIS_DISABLED) || 00756 (tbcd->nmcd.uItemState & CDIS_INDETERMINATE); 00757 BOOL pressed_look = !non_interactive_state && 00758 ((tbcd->nmcd.uItemState & CDIS_SELECTED) || 00759 (tbcd->nmcd.uItemState & CDIS_CHECKED)); 00760 00761 /* app don't want us to draw any edges */ 00762 if (dwItemCDFlag & TBCDRF_NOEDGES) 00763 return; 00764 00765 if (infoPtr->dwStyle & TBSTYLE_FLAT) 00766 { 00767 if (pressed_look) 00768 DrawEdge (hdc, &rc, BDR_SUNKENOUTER, BF_RECT); 00769 else if ((tbcd->nmcd.uItemState & CDIS_HOT) && !non_interactive_state) 00770 DrawEdge (hdc, &rc, BDR_RAISEDINNER, BF_RECT); 00771 } 00772 else 00773 { 00774 if (pressed_look) 00775 DrawEdge (hdc, &rc, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); 00776 else 00777 DrawEdge (hdc, &rc, EDGE_RAISED, 00778 BF_SOFT | BF_RECT | BF_MIDDLE); 00779 } 00780 } 00781 00782 static void 00783 TOOLBAR_DrawSepDDArrow(const TOOLBAR_INFO *infoPtr, const NMTBCUSTOMDRAW *tbcd, RECT *rcArrow, BOOL bDropDownPressed, DWORD dwItemCDFlag) 00784 { 00785 HDC hdc = tbcd->nmcd.hdc; 00786 int offset = 0; 00787 BOOL pressed = bDropDownPressed || 00788 (tbcd->nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)); 00789 00790 if (infoPtr->dwStyle & TBSTYLE_FLAT) 00791 { 00792 if (pressed) 00793 DrawEdge (hdc, rcArrow, BDR_SUNKENOUTER, BF_RECT); 00794 else if ( (tbcd->nmcd.uItemState & CDIS_HOT) && 00795 !(tbcd->nmcd.uItemState & CDIS_DISABLED) && 00796 !(tbcd->nmcd.uItemState & CDIS_INDETERMINATE)) 00797 DrawEdge (hdc, rcArrow, BDR_RAISEDINNER, BF_RECT); 00798 } 00799 else 00800 { 00801 if (pressed) 00802 DrawEdge (hdc, rcArrow, EDGE_SUNKEN, BF_RECT | BF_MIDDLE); 00803 else 00804 DrawEdge (hdc, rcArrow, EDGE_RAISED, 00805 BF_SOFT | BF_RECT | BF_MIDDLE); 00806 } 00807 00808 if (pressed) 00809 offset = (dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; 00810 00811 if (tbcd->nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 00812 { 00813 TOOLBAR_DrawArrow(hdc, rcArrow->left+1, rcArrow->top+1 + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); 00814 TOOLBAR_DrawArrow(hdc, rcArrow->left, rcArrow->top + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); 00815 } 00816 else 00817 TOOLBAR_DrawArrow(hdc, rcArrow->left + offset, rcArrow->top + offset + (rcArrow->bottom - rcArrow->top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 00818 } 00819 00820 /* draws a complete toolbar button */ 00821 static void 00822 TOOLBAR_DrawButton (const TOOLBAR_INFO *infoPtr, TBUTTON_INFO *btnPtr, HDC hdc, DWORD dwBaseCustDraw) 00823 { 00824 DWORD dwStyle = infoPtr->dwStyle; 00825 BOOL hasDropDownArrow = (TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && 00826 (btnPtr->fsStyle & BTNS_DROPDOWN)) || 00827 (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); 00828 BOOL drawSepDropDownArrow = hasDropDownArrow && 00829 (~btnPtr->fsStyle & BTNS_WHOLEDROPDOWN); 00830 RECT rc, rcArrow, rcBitmap, rcText; 00831 LPWSTR lpText = NULL; 00832 NMTBCUSTOMDRAW tbcd; 00833 DWORD ntfret; 00834 INT offset; 00835 INT oldBkMode; 00836 DWORD dwItemCustDraw; 00837 DWORD dwItemCDFlag; 00838 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 00839 00840 rc = btnPtr->rect; 00841 CopyRect (&rcArrow, &rc); 00842 00843 /* separator - doesn't send NM_CUSTOMDRAW */ 00844 if (btnPtr->fsStyle & BTNS_SEP) { 00845 if (theme) 00846 { 00847 DrawThemeBackground (theme, hdc, 00848 (dwStyle & CCS_VERT) ? TP_SEPARATORVERT : TP_SEPARATOR, 0, 00849 &rc, NULL); 00850 } 00851 else 00852 /* with the FLAT style, iBitmap is the width and has already */ 00853 /* been taken into consideration in calculating the width */ 00854 /* so now we need to draw the vertical separator */ 00855 /* empirical tests show that iBitmap can/will be non-zero */ 00856 /* when drawing the vertical bar... */ 00857 if ((dwStyle & TBSTYLE_FLAT) /* && (btnPtr->iBitmap == 0) */) { 00858 if (dwStyle & CCS_VERT) 00859 TOOLBAR_DrawFlatHorizontalSeparator (&rc, hdc, infoPtr); 00860 else 00861 TOOLBAR_DrawFlatSeparator (&rc, hdc, infoPtr); 00862 } 00863 else if (btnPtr->fsStyle != BTNS_SEP) { 00864 FIXME("Draw some kind of separator: fsStyle=%x\n", 00865 btnPtr->fsStyle); 00866 } 00867 return; 00868 } 00869 00870 /* get a pointer to the text */ 00871 lpText = TOOLBAR_GetText(infoPtr, btnPtr); 00872 00873 if (hasDropDownArrow) 00874 { 00875 int right; 00876 00877 if (dwStyle & TBSTYLE_FLAT) 00878 right = max(rc.left, rc.right - DDARROW_WIDTH); 00879 else 00880 right = max(rc.left, rc.right - DDARROW_WIDTH - 2); 00881 00882 if (drawSepDropDownArrow) 00883 rc.right = right; 00884 00885 rcArrow.left = right; 00886 } 00887 00888 /* copy text & bitmap rects after adjusting for drop-down arrow 00889 * so that text & bitmap is centered in the rectangle not containing 00890 * the arrow */ 00891 CopyRect(&rcText, &rc); 00892 CopyRect(&rcBitmap, &rc); 00893 00894 /* Center the bitmap horizontally and vertically */ 00895 if (dwStyle & TBSTYLE_LIST) 00896 { 00897 if (lpText && 00898 infoPtr->nMaxTextRows > 0 && 00899 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 00900 (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) 00901 rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->szPadding.cx / 2; 00902 else 00903 rcBitmap.left += GetSystemMetrics(SM_CXEDGE) + infoPtr->iListGap / 2; 00904 } 00905 else 00906 rcBitmap.left += ((rc.right - rc.left) - infoPtr->nBitmapWidth) / 2; 00907 00908 rcBitmap.top += infoPtr->szPadding.cy / 2; 00909 00910 TRACE("iBitmap=%d, start=(%d,%d) w=%d, h=%d\n", 00911 btnPtr->iBitmap, rcBitmap.left, rcBitmap.top, 00912 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 00913 TRACE("Text=%s\n", debugstr_w(lpText)); 00914 TRACE("iListGap=%d, padding = { %d, %d }\n", infoPtr->iListGap, infoPtr->szPadding.cx, infoPtr->szPadding.cy); 00915 00916 /* calculate text position */ 00917 if (lpText) 00918 { 00919 rcText.left += GetSystemMetrics(SM_CXEDGE); 00920 rcText.right -= GetSystemMetrics(SM_CXEDGE); 00921 if (dwStyle & TBSTYLE_LIST) 00922 { 00923 rcText.left += infoPtr->nBitmapWidth + infoPtr->iListGap + 2; 00924 } 00925 else 00926 { 00927 if (ImageList_GetImageCount(GETDEFIMAGELIST(infoPtr, 0)) > 0) 00928 rcText.top += infoPtr->szPadding.cy/2 + infoPtr->nBitmapHeight + 1; 00929 else 00930 rcText.top += infoPtr->szPadding.cy/2 + 2; 00931 } 00932 } 00933 00934 /* Initialize fields in all cases, because we use these later 00935 * NOTE: applications can and do alter these to customize their 00936 * toolbars */ 00937 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 00938 tbcd.clrText = comctl32_color.clrBtnText; 00939 tbcd.clrTextHighlight = comctl32_color.clrHighlightText; 00940 tbcd.clrBtnFace = comctl32_color.clrBtnFace; 00941 tbcd.clrBtnHighlight = comctl32_color.clrBtnHighlight; 00942 tbcd.clrMark = comctl32_color.clrHighlight; 00943 tbcd.clrHighlightHotTrack = 0; 00944 tbcd.nStringBkMode = TRANSPARENT; 00945 tbcd.nHLStringBkMode = OPAQUE; 00946 /* MSDN says that this is the text rectangle. 00947 * But (why always a but) tracing of v5.7 of native shows 00948 * that this is really a *relative* rectangle based on the 00949 * the nmcd.rc. Also the left and top are always 0 ignoring 00950 * any bitmap that might be present. */ 00951 tbcd.rcText.left = 0; 00952 tbcd.rcText.top = 0; 00953 tbcd.rcText.right = rcText.right - rc.left; 00954 tbcd.rcText.bottom = rcText.bottom - rc.top; 00955 tbcd.nmcd.uItemState = TOOLBAR_TranslateState(btnPtr); 00956 tbcd.nmcd.hdc = hdc; 00957 tbcd.nmcd.rc = rc; 00958 tbcd.hbrMonoDither = COMCTL32_hPattern55AABrush; 00959 00960 /* FIXME: what are these used for? */ 00961 tbcd.hbrLines = 0; 00962 tbcd.hpenLines = 0; 00963 00964 /* Issue Item Prepaint notify */ 00965 dwItemCustDraw = 0; 00966 dwItemCDFlag = 0; 00967 if (dwBaseCustDraw & CDRF_NOTIFYITEMDRAW) 00968 { 00969 tbcd.nmcd.dwDrawStage = CDDS_ITEMPREPAINT; 00970 tbcd.nmcd.dwItemSpec = btnPtr->idCommand; 00971 tbcd.nmcd.lItemlParam = btnPtr->dwData; 00972 ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 00973 /* reset these fields so the user can't alter the behaviour like native */ 00974 tbcd.nmcd.hdc = hdc; 00975 tbcd.nmcd.rc = rc; 00976 00977 dwItemCustDraw = ntfret & 0xffff; 00978 dwItemCDFlag = ntfret & 0xffff0000; 00979 if (dwItemCustDraw & CDRF_SKIPDEFAULT) 00980 return; 00981 /* save the only part of the rect that the user can change */ 00982 rcText.right = tbcd.rcText.right + rc.left; 00983 rcText.bottom = tbcd.rcText.bottom + rc.top; 00984 } 00985 00986 if (!(dwItemCDFlag & TBCDRF_NOOFFSET) && 00987 (btnPtr->fsState & (TBSTATE_PRESSED | TBSTATE_CHECKED))) 00988 OffsetRect(&rcText, 1, 1); 00989 00990 if (!(tbcd.nmcd.uItemState & CDIS_HOT) && 00991 ((tbcd.nmcd.uItemState & CDIS_CHECKED) || (tbcd.nmcd.uItemState & CDIS_INDETERMINATE))) 00992 TOOLBAR_DrawPattern (&rc, &tbcd); 00993 00994 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 00995 && (tbcd.nmcd.uItemState & CDIS_HOT)) 00996 { 00997 if ( dwItemCDFlag & TBCDRF_HILITEHOTTRACK ) 00998 { 00999 COLORREF oldclr; 01000 01001 oldclr = SetBkColor(hdc, tbcd.clrHighlightHotTrack); 01002 ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, 0); 01003 if (hasDropDownArrow) 01004 ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rcArrow, NULL, 0, 0); 01005 SetBkColor(hdc, oldclr); 01006 } 01007 } 01008 01009 if (theme) 01010 { 01011 int partId = drawSepDropDownArrow ? TP_SPLITBUTTON : TP_BUTTON; 01012 int stateId = TS_NORMAL; 01013 01014 if (tbcd.nmcd.uItemState & CDIS_DISABLED) 01015 stateId = TS_DISABLED; 01016 else if (tbcd.nmcd.uItemState & CDIS_SELECTED) 01017 stateId = TS_PRESSED; 01018 else if (tbcd.nmcd.uItemState & CDIS_CHECKED) 01019 stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT; 01020 else if ((tbcd.nmcd.uItemState & CDIS_HOT) 01021 || (drawSepDropDownArrow && btnPtr->bDropDownPressed)) 01022 stateId = TS_HOT; 01023 01024 DrawThemeBackground (theme, hdc, partId, stateId, &tbcd.nmcd.rc, NULL); 01025 } 01026 else 01027 TOOLBAR_DrawFrame(infoPtr, &tbcd, dwItemCDFlag); 01028 01029 if (drawSepDropDownArrow) 01030 { 01031 if (theme) 01032 { 01033 int stateId = TS_NORMAL; 01034 01035 if (tbcd.nmcd.uItemState & CDIS_DISABLED) 01036 stateId = TS_DISABLED; 01037 else if (btnPtr->bDropDownPressed || (tbcd.nmcd.uItemState & CDIS_SELECTED)) 01038 stateId = TS_PRESSED; 01039 else if (tbcd.nmcd.uItemState & CDIS_CHECKED) 01040 stateId = (tbcd.nmcd.uItemState & CDIS_HOT) ? TS_HOTCHECKED : TS_HOT; 01041 else if (tbcd.nmcd.uItemState & CDIS_HOT) 01042 stateId = TS_HOT; 01043 01044 DrawThemeBackground (theme, hdc, TP_DROPDOWNBUTTON, stateId, &rcArrow, NULL); 01045 DrawThemeBackground (theme, hdc, TP_SPLITBUTTONDROPDOWN, stateId, &rcArrow, NULL); 01046 } 01047 else 01048 TOOLBAR_DrawSepDDArrow(infoPtr, &tbcd, &rcArrow, btnPtr->bDropDownPressed, dwItemCDFlag); 01049 } 01050 01051 oldBkMode = SetBkMode (hdc, tbcd.nStringBkMode); 01052 if (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || (btnPtr->fsStyle & BTNS_SHOWTEXT)) 01053 TOOLBAR_DrawString (infoPtr, &rcText, lpText, &tbcd, dwItemCDFlag); 01054 SetBkMode (hdc, oldBkMode); 01055 01056 TOOLBAR_DrawImage(infoPtr, btnPtr, rcBitmap.left, rcBitmap.top, &tbcd, dwItemCDFlag); 01057 01058 if (hasDropDownArrow && !drawSepDropDownArrow) 01059 { 01060 if (tbcd.nmcd.uItemState & (CDIS_DISABLED | CDIS_INDETERMINATE)) 01061 { 01062 TOOLBAR_DrawArrow(hdc, rcArrow.left+1, rcArrow.top+1 + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnHighlight); 01063 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clr3dShadow); 01064 } 01065 else if (tbcd.nmcd.uItemState & (CDIS_SELECTED | CDIS_CHECKED)) 01066 { 01067 offset = (dwItemCDFlag & TBCDRF_NOOFFSET) ? 0 : 1; 01068 TOOLBAR_DrawArrow(hdc, rcArrow.left + offset, rcArrow.top + offset + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 01069 } 01070 else 01071 TOOLBAR_DrawArrow(hdc, rcArrow.left, rcArrow.top + (rcArrow.bottom - rcArrow.top - ARROW_HEIGHT) / 2, comctl32_color.clrBtnText); 01072 } 01073 01074 if (dwItemCustDraw & CDRF_NOTIFYPOSTPAINT) 01075 { 01076 tbcd.nmcd.dwDrawStage = CDDS_ITEMPOSTPAINT; 01077 TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 01078 } 01079 01080 } 01081 01082 01083 static void 01084 TOOLBAR_Refresh (TOOLBAR_INFO *infoPtr, HDC hdc, const PAINTSTRUCT *ps) 01085 { 01086 TBUTTON_INFO *btnPtr; 01087 INT i; 01088 RECT rcTemp, rcClient; 01089 NMTBCUSTOMDRAW tbcd; 01090 DWORD ntfret; 01091 DWORD dwBaseCustDraw; 01092 01093 /* the app has told us not to redraw the toolbar */ 01094 if (!infoPtr->bDoRedraw) 01095 return; 01096 01097 /* if imagelist belongs to the app, it can be changed 01098 by the app after setting it */ 01099 if (GETDEFIMAGELIST(infoPtr, 0) != infoPtr->himlInt) 01100 { 01101 infoPtr->nNumBitmaps = 0; 01102 for (i = 0; i < infoPtr->cimlDef; i++) 01103 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); 01104 } 01105 01106 TOOLBAR_DumpToolbar (infoPtr, __LINE__); 01107 01108 /* change the imagelist icon size if we manage the list and it is necessary */ 01109 TOOLBAR_CheckImageListIconSize(infoPtr); 01110 01111 /* Send initial notify */ 01112 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 01113 tbcd.nmcd.dwDrawStage = CDDS_PREPAINT; 01114 tbcd.nmcd.hdc = hdc; 01115 tbcd.nmcd.rc = ps->rcPaint; 01116 ntfret = TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 01117 dwBaseCustDraw = ntfret & 0xffff; 01118 01119 GetClientRect(infoPtr->hwndSelf, &rcClient); 01120 01121 /* redraw necessary buttons */ 01122 btnPtr = infoPtr->buttons; 01123 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) 01124 { 01125 BOOL bDraw; 01126 if (!RectVisible(hdc, &btnPtr->rect)) 01127 continue; 01128 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) 01129 { 01130 IntersectRect(&rcTemp, &rcClient, &btnPtr->rect); 01131 bDraw = EqualRect(&rcTemp, &btnPtr->rect); 01132 } 01133 else 01134 bDraw = TRUE; 01135 bDraw &= IntersectRect(&rcTemp, &(ps->rcPaint), &(btnPtr->rect)); 01136 bDraw = (btnPtr->fsState & TBSTATE_HIDDEN) ? FALSE : bDraw; 01137 if (bDraw) 01138 TOOLBAR_DrawButton(infoPtr, btnPtr, hdc, dwBaseCustDraw); 01139 } 01140 01141 /* draw insert mark if required */ 01142 if (infoPtr->tbim.iButton != -1) 01143 { 01144 RECT rcButton = infoPtr->buttons[infoPtr->tbim.iButton].rect; 01145 RECT rcInsertMark; 01146 rcInsertMark.top = rcButton.top; 01147 rcInsertMark.bottom = rcButton.bottom; 01148 if (infoPtr->tbim.dwFlags & TBIMHT_AFTER) 01149 rcInsertMark.left = rcInsertMark.right = rcButton.right; 01150 else 01151 rcInsertMark.left = rcInsertMark.right = rcButton.left - INSERTMARK_WIDTH; 01152 COMCTL32_DrawInsertMark(hdc, &rcInsertMark, infoPtr->clrInsertMark, FALSE); 01153 } 01154 01155 if (dwBaseCustDraw & CDRF_NOTIFYPOSTPAINT) 01156 { 01157 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 01158 tbcd.nmcd.dwDrawStage = CDDS_POSTPAINT; 01159 tbcd.nmcd.hdc = hdc; 01160 tbcd.nmcd.rc = ps->rcPaint; 01161 TOOLBAR_SendNotify(&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 01162 } 01163 } 01164 01165 /*********************************************************************** 01166 * TOOLBAR_MeasureString 01167 * 01168 * This function gets the width and height of a string in pixels. This 01169 * is done first by using GetTextExtentPoint to get the basic width 01170 * and height. The DrawText is called with DT_CALCRECT to get the exact 01171 * width. The reason is because the text may have more than one "&" (or 01172 * prefix characters as M$ likes to call them). The prefix character 01173 * indicates where the underline goes, except for the string "&&" which 01174 * is reduced to a single "&". GetTextExtentPoint does not process these 01175 * only DrawText does. Note that the BTNS_NOPREFIX is handled here. 01176 */ 01177 static void 01178 TOOLBAR_MeasureString(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *btnPtr, 01179 HDC hdc, LPSIZE lpSize) 01180 { 01181 RECT myrect; 01182 01183 lpSize->cx = 0; 01184 lpSize->cy = 0; 01185 01186 if (infoPtr->nMaxTextRows > 0 && 01187 !(btnPtr->fsState & TBSTATE_HIDDEN) && 01188 (!(infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 01189 (btnPtr->fsStyle & BTNS_SHOWTEXT)) ) 01190 { 01191 LPWSTR lpText = TOOLBAR_GetText(infoPtr, btnPtr); 01192 01193 if(lpText != NULL) { 01194 /* first get size of all the text */ 01195 GetTextExtentPoint32W (hdc, lpText, strlenW (lpText), lpSize); 01196 01197 /* feed above size into the rectangle for DrawText */ 01198 myrect.left = myrect.top = 0; 01199 myrect.right = lpSize->cx; 01200 myrect.bottom = lpSize->cy; 01201 01202 /* Use DrawText to get true size as drawn (less pesky "&") */ 01203 DrawTextW (hdc, lpText, -1, &myrect, DT_VCENTER | DT_SINGLELINE | 01204 DT_CALCRECT | ((btnPtr->fsStyle & BTNS_NOPREFIX) ? 01205 DT_NOPREFIX : 0)); 01206 01207 /* feed back to caller */ 01208 lpSize->cx = myrect.right; 01209 lpSize->cy = myrect.bottom; 01210 } 01211 } 01212 01213 TRACE("string size %d x %d!\n", lpSize->cx, lpSize->cy); 01214 } 01215 01216 /*********************************************************************** 01217 * TOOLBAR_CalcStrings 01218 * 01219 * This function walks through each string and measures it and returns 01220 * the largest height and width to caller. 01221 */ 01222 static void 01223 TOOLBAR_CalcStrings (const TOOLBAR_INFO *infoPtr, LPSIZE lpSize) 01224 { 01225 TBUTTON_INFO *btnPtr; 01226 INT i; 01227 SIZE sz; 01228 HDC hdc; 01229 HFONT hOldFont; 01230 01231 lpSize->cx = 0; 01232 lpSize->cy = 0; 01233 01234 if (infoPtr->nMaxTextRows == 0) 01235 return; 01236 01237 hdc = GetDC (infoPtr->hwndSelf); 01238 hOldFont = SelectObject (hdc, infoPtr->hFont); 01239 01240 if (infoPtr->nNumButtons == 0 && infoPtr->nNumStrings > 0) 01241 { 01242 TEXTMETRICW tm; 01243 01244 GetTextMetricsW(hdc, &tm); 01245 lpSize->cy = tm.tmHeight; 01246 } 01247 01248 btnPtr = infoPtr->buttons; 01249 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 01250 if(TOOLBAR_HasText(infoPtr, btnPtr)) 01251 { 01252 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); 01253 if (sz.cx > lpSize->cx) 01254 lpSize->cx = sz.cx; 01255 if (sz.cy > lpSize->cy) 01256 lpSize->cy = sz.cy; 01257 } 01258 } 01259 01260 SelectObject (hdc, hOldFont); 01261 ReleaseDC (infoPtr->hwndSelf, hdc); 01262 01263 TRACE("max string size %d x %d!\n", lpSize->cx, lpSize->cy); 01264 } 01265 01266 /*********************************************************************** 01267 * TOOLBAR_WrapToolbar 01268 * 01269 * This function walks through the buttons and separators in the 01270 * toolbar, and sets the TBSTATE_WRAP flag only on those items where 01271 * wrapping should occur based on the width of the toolbar window. 01272 * It does *not* calculate button placement itself. That task 01273 * takes place in TOOLBAR_CalcToolbar. If the program wants to manage 01274 * the toolbar wrapping on its own, it can use the TBSTYLE_WRAPABLE 01275 * flag, and set the TBSTATE_WRAP flags manually on the appropriate items. 01276 * 01277 * Note: TBSTYLE_WRAPABLE or TBSTYLE_EX_UNDOC1 can be used also to allow 01278 * vertical toolbar lists. 01279 */ 01280 01281 static void 01282 TOOLBAR_WrapToolbar(TOOLBAR_INFO *infoPtr) 01283 { 01284 TBUTTON_INFO *btnPtr; 01285 INT x, cx, i, j; 01286 RECT rc; 01287 BOOL bButtonWrap; 01288 01289 /* When the toolbar window style is not TBSTYLE_WRAPABLE, */ 01290 /* no layout is necessary. Applications may use this style */ 01291 /* to perform their own layout on the toolbar. */ 01292 if( !(infoPtr->dwStyle & TBSTYLE_WRAPABLE) && 01293 !(infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1) ) return; 01294 01295 btnPtr = infoPtr->buttons; 01296 x = infoPtr->nIndent; 01297 01298 if (GetParent(infoPtr->hwndSelf)) 01299 { 01300 /* this can get the parents width, to know how far we can extend 01301 * this toolbar. We cannot use its height, as there may be multiple 01302 * toolbars in a rebar control 01303 */ 01304 GetClientRect( GetParent(infoPtr->hwndSelf), &rc ); 01305 infoPtr->nWidth = rc.right - rc.left; 01306 } 01307 else 01308 { 01309 GetWindowRect( infoPtr->hwndSelf, &rc ); 01310 infoPtr->nWidth = rc.right - rc.left; 01311 } 01312 01313 bButtonWrap = FALSE; 01314 01315 TRACE("start ButtonWidth=%d, BitmapWidth=%d, nWidth=%d, nIndent=%d\n", 01316 infoPtr->nButtonWidth, infoPtr->nBitmapWidth, infoPtr->nWidth, 01317 infoPtr->nIndent); 01318 01319 for (i = 0; i < infoPtr->nNumButtons; i++ ) 01320 { 01321 btnPtr[i].fsState &= ~TBSTATE_WRAP; 01322 01323 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 01324 continue; 01325 01326 if (btnPtr[i].cx > 0) 01327 cx = btnPtr[i].cx; 01328 /* horizontal separators are treated as buttons for width */ 01329 else if ((btnPtr[i].fsStyle & BTNS_SEP) && 01330 !(infoPtr->dwStyle & CCS_VERT)) 01331 cx = (btnPtr[i].iBitmap > 0) ? btnPtr[i].iBitmap : SEPARATOR_WIDTH; 01332 else 01333 cx = infoPtr->nButtonWidth; 01334 01335 /* Two or more adjacent separators form a separator group. */ 01336 /* The first separator in a group should be wrapped to the */ 01337 /* next row if the previous wrapping is on a button. */ 01338 if( bButtonWrap && 01339 (btnPtr[i].fsStyle & BTNS_SEP) && 01340 (i + 1 < infoPtr->nNumButtons ) && 01341 (btnPtr[i + 1].fsStyle & BTNS_SEP) ) 01342 { 01343 TRACE("wrap point 1 btn %d style %02x\n", i, btnPtr[i].fsStyle); 01344 btnPtr[i].fsState |= TBSTATE_WRAP; 01345 x = infoPtr->nIndent; 01346 i++; 01347 bButtonWrap = FALSE; 01348 continue; 01349 } 01350 01351 /* The layout makes sure the bitmap is visible, but not the button. */ 01352 /* Test added to also wrap after a button that starts a row but */ 01353 /* is bigger than the area. - GA 8/01 */ 01354 if (( x + cx - (infoPtr->nButtonWidth - infoPtr->nBitmapWidth) / 2 01355 > infoPtr->nWidth ) || 01356 ((x == infoPtr->nIndent) && (cx > infoPtr->nWidth))) 01357 { 01358 BOOL bFound = FALSE; 01359 01360 /* If the current button is a separator and not hidden, */ 01361 /* go to the next until it reaches a non separator. */ 01362 /* Wrap the last separator if it is before a button. */ 01363 while( ( ((btnPtr[i].fsStyle & BTNS_SEP) && 01364 !(btnPtr[i].fsStyle & BTNS_DROPDOWN)) || 01365 (btnPtr[i].fsState & TBSTATE_HIDDEN) ) && 01366 i < infoPtr->nNumButtons ) 01367 { 01368 i++; 01369 bFound = TRUE; 01370 } 01371 01372 if( bFound && i < infoPtr->nNumButtons ) 01373 { 01374 i--; 01375 TRACE("wrap point 2 btn %d style %02x, x=%d, cx=%d\n", 01376 i, btnPtr[i].fsStyle, x, cx); 01377 btnPtr[i].fsState |= TBSTATE_WRAP; 01378 x = infoPtr->nIndent; 01379 bButtonWrap = FALSE; 01380 continue; 01381 } 01382 else if ( i >= infoPtr->nNumButtons) 01383 break; 01384 01385 /* If the current button is not a separator, find the last */ 01386 /* separator and wrap it. */ 01387 for ( j = i - 1; j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) 01388 { 01389 if ((btnPtr[j].fsStyle & BTNS_SEP) && 01390 !(btnPtr[j].fsState & TBSTATE_HIDDEN)) 01391 { 01392 bFound = TRUE; 01393 i = j; 01394 TRACE("wrap point 3 btn %d style %02x, x=%d, cx=%d\n", 01395 i, btnPtr[i].fsStyle, x, cx); 01396 x = infoPtr->nIndent; 01397 btnPtr[j].fsState |= TBSTATE_WRAP; 01398 bButtonWrap = FALSE; 01399 break; 01400 } 01401 } 01402 01403 /* If no separator available for wrapping, wrap one of */ 01404 /* non-hidden previous button. */ 01405 if (!bFound) 01406 { 01407 for ( j = i - 1; 01408 j >= 0 && !(btnPtr[j].fsState & TBSTATE_WRAP); j--) 01409 { 01410 if (btnPtr[j].fsState & TBSTATE_HIDDEN) 01411 continue; 01412 01413 bFound = TRUE; 01414 i = j; 01415 TRACE("wrap point 4 btn %d style %02x, x=%d, cx=%d\n", 01416 i, btnPtr[i].fsStyle, x, cx); 01417 x = infoPtr->nIndent; 01418 btnPtr[j].fsState |= TBSTATE_WRAP; 01419 bButtonWrap = TRUE; 01420 break; 01421 } 01422 } 01423 01424 /* If all above failed, wrap the current button. */ 01425 if (!bFound) 01426 { 01427 TRACE("wrap point 5 btn %d style %02x, x=%d, cx=%d\n", 01428 i, btnPtr[i].fsStyle, x, cx); 01429 btnPtr[i].fsState |= TBSTATE_WRAP; 01430 x = infoPtr->nIndent; 01431 if (btnPtr[i].fsStyle & BTNS_SEP ) 01432 bButtonWrap = FALSE; 01433 else 01434 bButtonWrap = TRUE; 01435 } 01436 } 01437 else { 01438 TRACE("wrap point 6 btn %d style %02x, x=%d, cx=%d\n", 01439 i, btnPtr[i].fsStyle, x, cx); 01440 x += cx; 01441 } 01442 } 01443 } 01444 01445 01446 /*********************************************************************** 01447 * TOOLBAR_MeasureButton 01448 * 01449 * Calculates the width and height required for a button. Used in 01450 * TOOLBAR_CalcToolbar to set the all-button width and height and also for 01451 * the width of buttons that are autosized. 01452 * 01453 * Note that it would have been rather elegant to use one piece of code for 01454 * both the laying out of the toolbar and for controlling where button parts 01455 * are drawn, but the native control has inconsistencies between the two that 01456 * prevent this from being effectively. These inconsistencies can be seen as 01457 * artefacts where parts of the button appear outside of the bounding button 01458 * rectangle. 01459 * 01460 * There are several cases for the calculation of the button dimensions and 01461 * button part positioning: 01462 * 01463 * List 01464 * ==== 01465 * 01466 * With Bitmap: 01467 * 01468 * +--------------------------------------------------------+ ^ 01469 * | ^ ^ | | 01470 * | | pad.cy / 2 | centered | | 01471 * | pad.cx/2 + cxedge +--------------+ +------------+ | | DEFPAD_CY + 01472 * |<----------------->| nBitmapWidth | | Text | | | max(nBitmapHeight, szText.cy) 01473 * | |<------------>| | | | | 01474 * | +--------------+ +------------+ | | 01475 * |<-------------------------------------->| | | 01476 * | cxedge + iListGap + nBitmapWidth + 2 |<-----------> | | 01477 * | szText.cx | | 01478 * +--------------------------------------------------------+ - 01479 * <--------------------------------------------------------> 01480 * 2*cxedge + nBitmapWidth + iListGap + szText.cx + pad.cx 01481 * 01482 * Without Bitmap (I_IMAGENONE): 01483 * 01484 * +-----------------------------------+ ^ 01485 * | ^ | | 01486 * | | centered | | LISTPAD_CY + 01487 * | +------------+ | | szText.cy 01488 * | | Text | | | 01489 * | | | | | 01490 * | +------------+ | | 01491 * |<----------------->| | | 01492 * | cxedge |<-----------> | | 01493 * | szText.cx | | 01494 * +-----------------------------------+ - 01495 * <-----------------------------------> 01496 * szText.cx + pad.cx 01497 * 01498 * Without text: 01499 * 01500 * +--------------------------------------+ ^ 01501 * | ^ | | 01502 * | | padding.cy/2 | | DEFPAD_CY + 01503 * | +------------+ | | nBitmapHeight 01504 * | | Bitmap | | | 01505 * | | | | | 01506 * | +------------+ | | 01507 * |<------------------->| | | 01508 * | cxedge + iListGap/2 |<-----------> | | 01509 * | nBitmapWidth | | 01510 * +--------------------------------------+ - 01511 * <--------------------------------------> 01512 * 2*cxedge + nBitmapWidth + iListGap 01513 * 01514 * Non-List 01515 * ======== 01516 * 01517 * With bitmap: 01518 * 01519 * +-----------------------------------+ ^ 01520 * | ^ | | 01521 * | | pad.cy / 2 | | nBitmapHeight + 01522 * | - | | szText.cy + 01523 * | +------------+ | | DEFPAD_CY + 1 01524 * | centered | Bitmap | | | 01525 * |<----------------->| | | | 01526 * | +------------+ | | 01527 * | ^ | | 01528 * | 1 | | | 01529 * | - | | 01530 * | centered +---------------+ | | 01531 * |<--------------->| Text | | | 01532 * | +---------------+ | | 01533 * +-----------------------------------+ - 01534 * <-----------------------------------> 01535 * pad.cx + max(nBitmapWidth, szText.cx) 01536 * 01537 * Without bitmaps (NULL imagelist or ImageList_GetImageCount() = 0): 01538 * 01539 * +---------------------------------------+ ^ 01540 * | ^ | | 01541 * | | 2 + pad.cy / 2 | | 01542 * | - | | szText.cy + 01543 * | centered +-----------------+ | | pad.cy + 2 01544 * |<--------------->| Text | | | 01545 * | +-----------------+ | | 01546 * | | | 01547 * +---------------------------------------+ - 01548 * <---------------------------------------> 01549 * 2*cxedge + pad.cx + szText.cx 01550 * 01551 * Without text: 01552 * As for with bitmaps, but with szText.cx zero. 01553 */ 01554 static inline SIZE TOOLBAR_MeasureButton(const TOOLBAR_INFO *infoPtr, SIZE sizeString, 01555 BOOL bHasBitmap, BOOL bValidImageList) 01556 { 01557 SIZE sizeButton; 01558 if (infoPtr->dwStyle & TBSTYLE_LIST) 01559 { 01560 /* set button height from bitmap / text height... */ 01561 sizeButton.cy = max((bHasBitmap ? infoPtr->nBitmapHeight : 0), 01562 sizeString.cy); 01563 01564 /* ... add on the necessary padding */ 01565 if (bValidImageList) 01566 { 01567 if (bHasBitmap) 01568 sizeButton.cy += DEFPAD_CY; 01569 else 01570 sizeButton.cy += LISTPAD_CY; 01571 } 01572 else 01573 sizeButton.cy += infoPtr->szPadding.cy; 01574 01575 /* calculate button width */ 01576 sizeButton.cx = 2*GetSystemMetrics(SM_CXEDGE) + 01577 infoPtr->nBitmapWidth + infoPtr->iListGap; 01578 if (sizeString.cx > 0) 01579 sizeButton.cx += sizeString.cx + infoPtr->szPadding.cx; 01580 01581 } 01582 else 01583 { 01584 if (bHasBitmap) 01585 { 01586 sizeButton.cy = infoPtr->nBitmapHeight + DEFPAD_CY; 01587 if (sizeString.cy > 0) 01588 sizeButton.cy += 1 + sizeString.cy; 01589 sizeButton.cx = infoPtr->szPadding.cx + 01590 max(sizeString.cx, infoPtr->nBitmapWidth); 01591 } 01592 else 01593 { 01594 sizeButton.cy = sizeString.cy + infoPtr->szPadding.cy + 01595 NONLIST_NOTEXT_OFFSET; 01596 sizeButton.cx = infoPtr->szPadding.cx + 01597 max(2*GetSystemMetrics(SM_CXEDGE) + sizeString.cx, infoPtr->nBitmapWidth); 01598 } 01599 } 01600 return sizeButton; 01601 } 01602 01603 01604 /*********************************************************************** 01605 * TOOLBAR_CalcToolbar 01606 * 01607 * This function calculates button and separator placement. It first 01608 * calculates the button sizes, gets the toolbar window width and then 01609 * calls TOOLBAR_WrapToolbar to determine which buttons we need to wrap 01610 * on. It assigns a new location to each item and sends this location to 01611 * the tooltip window if appropriate. Finally, it updates the rcBound 01612 * rect and calculates the new required toolbar window height. 01613 */ 01614 static void 01615 TOOLBAR_CalcToolbar (TOOLBAR_INFO *infoPtr) 01616 { 01617 SIZE sizeString, sizeButton; 01618 BOOL validImageList = FALSE; 01619 01620 TOOLBAR_CalcStrings (infoPtr, &sizeString); 01621 01622 TOOLBAR_DumpToolbar (infoPtr, __LINE__); 01623 01624 if (TOOLBAR_IsValidImageList(infoPtr, 0)) 01625 validImageList = TRUE; 01626 sizeButton = TOOLBAR_MeasureButton(infoPtr, sizeString, TRUE, validImageList); 01627 infoPtr->nButtonWidth = sizeButton.cx; 01628 infoPtr->nButtonHeight = sizeButton.cy; 01629 infoPtr->iTopMargin = default_top_margin(infoPtr); 01630 01631 if ( infoPtr->cxMin >= 0 && infoPtr->nButtonWidth < infoPtr->cxMin ) 01632 infoPtr->nButtonWidth = infoPtr->cxMin; 01633 if ( infoPtr->cxMax > 0 && infoPtr->nButtonWidth > infoPtr->cxMax ) 01634 infoPtr->nButtonWidth = infoPtr->cxMax; 01635 01636 TOOLBAR_LayoutToolbar(infoPtr); 01637 } 01638 01639 static void 01640 TOOLBAR_LayoutToolbar(TOOLBAR_INFO *infoPtr) 01641 { 01642 TBUTTON_INFO *btnPtr; 01643 SIZE sizeButton; 01644 INT i, nRows, nSepRows; 01645 INT x, y, cx, cy; 01646 BOOL bWrap; 01647 BOOL validImageList = TOOLBAR_IsValidImageList(infoPtr, 0); 01648 BOOL hasDropDownArrows = TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle); 01649 01650 TOOLBAR_WrapToolbar(infoPtr); 01651 01652 x = infoPtr->nIndent; 01653 y = infoPtr->iTopMargin; 01654 cx = infoPtr->nButtonWidth; 01655 cy = infoPtr->nButtonHeight; 01656 01657 nRows = nSepRows = 0; 01658 01659 infoPtr->rcBound.top = y; 01660 infoPtr->rcBound.left = x; 01661 infoPtr->rcBound.bottom = y + cy; 01662 infoPtr->rcBound.right = x; 01663 01664 btnPtr = infoPtr->buttons; 01665 01666 TRACE("cy=%d\n", cy); 01667 01668 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++ ) 01669 { 01670 bWrap = FALSE; 01671 if (btnPtr->fsState & TBSTATE_HIDDEN) 01672 { 01673 SetRectEmpty (&btnPtr->rect); 01674 continue; 01675 } 01676 01677 cy = infoPtr->nButtonHeight; 01678 01679 if (btnPtr->fsStyle & BTNS_SEP) { 01680 if (infoPtr->dwStyle & CCS_VERT) { 01681 cy = (btnPtr->iBitmap > 0) ? btnPtr->iBitmap : SEPARATOR_WIDTH; 01682 cx = (btnPtr->cx > 0) ? btnPtr->cx : infoPtr->nWidth; 01683 } 01684 else 01685 cx = (btnPtr->cx > 0) ? btnPtr->cx : 01686 (btnPtr->iBitmap > 0) ? btnPtr->iBitmap : SEPARATOR_WIDTH; 01687 } 01688 else 01689 { 01690 if (btnPtr->cx) 01691 cx = btnPtr->cx; 01692 else if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) || 01693 (btnPtr->fsStyle & BTNS_AUTOSIZE)) 01694 { 01695 SIZE sz; 01696 HDC hdc; 01697 HFONT hOldFont; 01698 01699 hdc = GetDC (infoPtr->hwndSelf); 01700 hOldFont = SelectObject (hdc, infoPtr->hFont); 01701 01702 TOOLBAR_MeasureString(infoPtr, btnPtr, hdc, &sz); 01703 01704 SelectObject (hdc, hOldFont); 01705 ReleaseDC (infoPtr->hwndSelf, hdc); 01706 01707 sizeButton = TOOLBAR_MeasureButton(infoPtr, sz, 01708 TOOLBAR_IsValidBitmapIndex(infoPtr, infoPtr->buttons[i].iBitmap), 01709 validImageList); 01710 cx = sizeButton.cx; 01711 } 01712 else 01713 cx = infoPtr->nButtonWidth; 01714 01715 /* if size has been set manually then don't add on extra space 01716 * for the drop down arrow */ 01717 if (!btnPtr->cx && hasDropDownArrows && 01718 ((btnPtr->fsStyle & BTNS_DROPDOWN) || (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN))) 01719 cx += DDARROW_WIDTH; 01720 } 01721 if (btnPtr->fsState & TBSTATE_WRAP ) 01722 bWrap = TRUE; 01723 01724 SetRect (&btnPtr->rect, x, y, x + cx, y + cy); 01725 01726 if (infoPtr->rcBound.left > x) 01727 infoPtr->rcBound.left = x; 01728 if (infoPtr->rcBound.right < x + cx) 01729 infoPtr->rcBound.right = x + cx; 01730 if (infoPtr->rcBound.bottom < y + cy) 01731 infoPtr->rcBound.bottom = y + cy; 01732 01733 TOOLBAR_TooltipSetRect(infoPtr, btnPtr); 01734 01735 /* btnPtr->nRow is zero based. The space between the rows is */ 01736 /* also considered as a row. */ 01737 btnPtr->nRow = nRows + nSepRows; 01738 01739 TRACE("button %d style=%x, bWrap=%d, nRows=%d, nSepRows=%d, btnrow=%d, (%d,%d)-(%d,%d)\n", 01740 i, btnPtr->fsStyle, bWrap, nRows, nSepRows, btnPtr->nRow, 01741 x, y, x+cx, y+cy); 01742 01743 if( bWrap ) 01744 { 01745 if ( !(btnPtr->fsStyle & BTNS_SEP) ) 01746 y += cy; 01747 else 01748 { 01749 if ( !(infoPtr->dwStyle & CCS_VERT)) 01750 y += cy + ( (btnPtr->cx > 0 ) ? 01751 btnPtr->cx : SEPARATOR_WIDTH) * 2 /3; 01752 else 01753 y += cy; 01754 01755 /* nSepRows is used to calculate the extra height following */ 01756 /* the last row. */ 01757 nSepRows++; 01758 } 01759 x = infoPtr->nIndent; 01760 01761 /* Increment row number unless this is the last button */ 01762 /* and it has Wrap set. */ 01763 if (i != infoPtr->nNumButtons-1) 01764 nRows++; 01765 } 01766 else 01767 x += cx; 01768 } 01769 01770 /* infoPtr->nRows is the number of rows on the toolbar */ 01771 infoPtr->nRows = nRows + nSepRows + 1; 01772 01773 TRACE("toolbar button width %d\n", infoPtr->nButtonWidth); 01774 } 01775 01776 01777 static INT 01778 TOOLBAR_InternalHitTest (const TOOLBAR_INFO *infoPtr, const POINT *lpPt) 01779 { 01780 TBUTTON_INFO *btnPtr; 01781 INT i; 01782 01783 btnPtr = infoPtr->buttons; 01784 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 01785 if (btnPtr->fsState & TBSTATE_HIDDEN) 01786 continue; 01787 01788 if (btnPtr->fsStyle & BTNS_SEP) { 01789 if (PtInRect (&btnPtr->rect, *lpPt)) { 01790 TRACE(" ON SEPARATOR %d!\n", i); 01791 return -i; 01792 } 01793 } 01794 else { 01795 if (PtInRect (&btnPtr->rect, *lpPt)) { 01796 TRACE(" ON BUTTON %d!\n", i); 01797 return i; 01798 } 01799 } 01800 } 01801 01802 TRACE(" NOWHERE!\n"); 01803 return TOOLBAR_NOWHERE; 01804 } 01805 01806 01807 /* worker for TB_ADDBUTTONS and TB_INSERTBUTTON */ 01808 static BOOL 01809 TOOLBAR_InternalInsertButtonsT(TOOLBAR_INFO *infoPtr, INT iIndex, UINT nAddButtons, const TBBUTTON *lpTbb, BOOL fUnicode) 01810 { 01811 INT nOldButtons, nNewButtons, iButton; 01812 BOOL fHasString = FALSE; 01813 01814 if (iIndex < 0) /* iIndex can be negative, what means adding at the end */ 01815 iIndex = infoPtr->nNumButtons; 01816 01817 nOldButtons = infoPtr->nNumButtons; 01818 nNewButtons = nOldButtons + nAddButtons; 01819 01820 infoPtr->buttons = ReAlloc(infoPtr->buttons, sizeof(TBUTTON_INFO)*nNewButtons); 01821 memmove(&infoPtr->buttons[iIndex + nAddButtons], &infoPtr->buttons[iIndex], 01822 (nOldButtons - iIndex) * sizeof(TBUTTON_INFO)); 01823 infoPtr->nNumButtons += nAddButtons; 01824 01825 /* insert new buttons data */ 01826 for (iButton = 0; iButton < nAddButtons; iButton++) { 01827 TBUTTON_INFO *btnPtr = &infoPtr->buttons[iIndex + iButton]; 01828 01829 TOOLBAR_DumpTBButton(lpTbb + iButton, fUnicode); 01830 01831 ZeroMemory(btnPtr, sizeof(*btnPtr)); 01832 01833 btnPtr->iBitmap = lpTbb[iButton].iBitmap; 01834 btnPtr->idCommand = lpTbb[iButton].idCommand; 01835 btnPtr->fsState = lpTbb[iButton].fsState; 01836 btnPtr->fsStyle = lpTbb[iButton].fsStyle; 01837 btnPtr->dwData = lpTbb[iButton].dwData; 01838 if (btnPtr->fsStyle & BTNS_SEP) 01839 btnPtr->iString = -1; 01840 else if(!IS_INTRESOURCE(lpTbb[iButton].iString) && lpTbb[iButton].iString != -1) 01841 { 01842 if (fUnicode) 01843 Str_SetPtrW((LPWSTR*)&btnPtr->iString, (LPWSTR)lpTbb[iButton].iString ); 01844 else 01845 Str_SetPtrAtoW((LPWSTR*)&btnPtr->iString, (LPSTR)lpTbb[iButton].iString); 01846 fHasString = TRUE; 01847 } 01848 else 01849 btnPtr->iString = lpTbb[iButton].iString; 01850 01851 TOOLBAR_TooltipAddTool(infoPtr, btnPtr); 01852 } 01853 01854 if (infoPtr->nNumStrings > 0 || fHasString) 01855 TOOLBAR_CalcToolbar(infoPtr); 01856 else 01857 TOOLBAR_LayoutToolbar(infoPtr); 01858 TOOLBAR_AutoSize(infoPtr); 01859 01860 TOOLBAR_DumpToolbar(infoPtr, __LINE__); 01861 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 01862 return TRUE; 01863 } 01864 01865 01866 static INT 01867 TOOLBAR_GetButtonIndex (const TOOLBAR_INFO *infoPtr, INT idCommand, BOOL CommandIsIndex) 01868 { 01869 TBUTTON_INFO *btnPtr; 01870 INT i; 01871 01872 if (CommandIsIndex) { 01873 TRACE("command is really index command=%d\n", idCommand); 01874 if (idCommand >= infoPtr->nNumButtons) return -1; 01875 return idCommand; 01876 } 01877 btnPtr = infoPtr->buttons; 01878 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) { 01879 if (btnPtr->idCommand == idCommand) { 01880 TRACE("command=%d index=%d\n", idCommand, i); 01881 return i; 01882 } 01883 } 01884 TRACE("no index found for command=%d\n", idCommand); 01885 return -1; 01886 } 01887 01888 01889 static INT 01890 TOOLBAR_GetCheckedGroupButtonIndex (const TOOLBAR_INFO *infoPtr, INT nIndex) 01891 { 01892 TBUTTON_INFO *btnPtr; 01893 INT nRunIndex; 01894 01895 if ((nIndex < 0) || (nIndex > infoPtr->nNumButtons)) 01896 return -1; 01897 01898 /* check index button */ 01899 btnPtr = &infoPtr->buttons[nIndex]; 01900 if ((btnPtr->fsStyle & BTNS_CHECKGROUP) == BTNS_CHECKGROUP) { 01901 if (btnPtr->fsState & TBSTATE_CHECKED) 01902 return nIndex; 01903 } 01904 01905 /* check previous buttons */ 01906 nRunIndex = nIndex - 1; 01907 while (nRunIndex >= 0) { 01908 btnPtr = &infoPtr->buttons[nRunIndex]; 01909 if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) { 01910 if (btnPtr->fsState & TBSTATE_CHECKED) 01911 return nRunIndex; 01912 } 01913 else 01914 break; 01915 nRunIndex--; 01916 } 01917 01918 /* check next buttons */ 01919 nRunIndex = nIndex + 1; 01920 while (nRunIndex < infoPtr->nNumButtons) { 01921 btnPtr = &infoPtr->buttons[nRunIndex]; 01922 if ((btnPtr->fsStyle & BTNS_GROUP) == BTNS_GROUP) { 01923 if (btnPtr->fsState & TBSTATE_CHECKED) 01924 return nRunIndex; 01925 } 01926 else 01927 break; 01928 nRunIndex++; 01929 } 01930 01931 return -1; 01932 } 01933 01934 01935 static VOID 01936 TOOLBAR_RelayEvent (HWND hwndTip, HWND hwndMsg, UINT uMsg, 01937 WPARAM wParam, LPARAM lParam) 01938 { 01939 MSG msg; 01940 01941 msg.hwnd = hwndMsg; 01942 msg.message = uMsg; 01943 msg.wParam = wParam; 01944 msg.lParam = lParam; 01945 msg.time = GetMessageTime (); 01946 msg.pt.x = (short)LOWORD(GetMessagePos ()); 01947 msg.pt.y = (short)HIWORD(GetMessagePos ()); 01948 01949 SendMessageW (hwndTip, TTM_RELAYEVENT, 0, (LPARAM)&msg); 01950 } 01951 01952 static void 01953 TOOLBAR_TooltipAddTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 01954 { 01955 if (infoPtr->hwndToolTip && !(button->fsStyle & BTNS_SEP)) { 01956 TTTOOLINFOW ti; 01957 01958 ZeroMemory(&ti, sizeof(TTTOOLINFOW)); 01959 ti.cbSize = sizeof (TTTOOLINFOW); 01960 ti.hwnd = infoPtr->hwndSelf; 01961 ti.uId = button->idCommand; 01962 ti.hinst = 0; 01963 ti.lpszText = LPSTR_TEXTCALLBACKW; 01964 /* ti.lParam = random value from the stack? */ 01965 01966 SendMessageW(infoPtr->hwndToolTip, TTM_ADDTOOLW, 01967 0, (LPARAM)&ti); 01968 } 01969 } 01970 01971 static void 01972 TOOLBAR_TooltipDelTool(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 01973 { 01974 if ((infoPtr->hwndToolTip) && !(button->fsStyle & BTNS_SEP)) { 01975 TTTOOLINFOW ti; 01976 01977 ZeroMemory(&ti, sizeof(ti)); 01978 ti.cbSize = sizeof(ti); 01979 ti.hwnd = infoPtr->hwndSelf; 01980 ti.uId = button->idCommand; 01981 01982 SendMessageW(infoPtr->hwndToolTip, TTM_DELTOOLW, 0, (LPARAM)&ti); 01983 } 01984 } 01985 01986 static void TOOLBAR_TooltipSetRect(const TOOLBAR_INFO *infoPtr, const TBUTTON_INFO *button) 01987 { 01988 /* Set the toolTip only for non-hidden, non-separator button */ 01989 if (infoPtr->hwndToolTip && !(button->fsStyle & BTNS_SEP)) 01990 { 01991 TTTOOLINFOW ti; 01992 01993 ZeroMemory(&ti, sizeof(ti)); 01994 ti.cbSize = sizeof(ti); 01995 ti.hwnd = infoPtr->hwndSelf; 01996 ti.uId = button->idCommand; 01997 ti.rect = button->rect; 01998 SendMessageW(infoPtr->hwndToolTip, TTM_NEWTOOLRECTW, 0, (LPARAM)&ti); 01999 } 02000 } 02001 02002 /* Creates the tooltip control */ 02003 static void 02004 TOOLBAR_TooltipCreateControl(TOOLBAR_INFO *infoPtr) 02005 { 02006 int i; 02007 NMTOOLTIPSCREATED nmttc; 02008 02009 infoPtr->hwndToolTip = CreateWindowExW(0, TOOLTIPS_CLASSW, NULL, WS_POPUP, 02010 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 02011 infoPtr->hwndSelf, 0, 0, 0); 02012 02013 if (!infoPtr->hwndToolTip) 02014 return; 02015 02016 /* Send NM_TOOLTIPSCREATED notification */ 02017 nmttc.hwndToolTips = infoPtr->hwndToolTip; 02018 TOOLBAR_SendNotify(&nmttc.hdr, infoPtr, NM_TOOLTIPSCREATED); 02019 02020 for (i = 0; i < infoPtr->nNumButtons; i++) 02021 { 02022 TOOLBAR_TooltipAddTool(infoPtr, &infoPtr->buttons[i]); 02023 TOOLBAR_TooltipSetRect(infoPtr, &infoPtr->buttons[i]); 02024 } 02025 } 02026 02027 /* keeps available button list box sorted by button id */ 02028 static void TOOLBAR_Cust_InsertAvailButton(HWND hwnd, PCUSTOMBUTTON btnInfoNew) 02029 { 02030 int i; 02031 int count; 02032 PCUSTOMBUTTON btnInfo; 02033 HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 02034 02035 TRACE("button %s, idCommand %d\n", debugstr_w(btnInfoNew->text), btnInfoNew->btn.idCommand); 02036 02037 count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); 02038 02039 /* position 0 is always separator */ 02040 for (i = 1; i < count; i++) 02041 { 02042 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, i, 0); 02043 if (btnInfoNew->btn.idCommand < btnInfo->btn.idCommand) 02044 { 02045 i = SendMessageW(hwndAvail, LB_INSERTSTRING, i, 0); 02046 SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); 02047 return; 02048 } 02049 } 02050 /* id higher than all others add to end */ 02051 i = SendMessageW(hwndAvail, LB_ADDSTRING, 0, 0); 02052 SendMessageW(hwndAvail, LB_SETITEMDATA, i, (LPARAM)btnInfoNew); 02053 } 02054 02055 static void TOOLBAR_Cust_MoveButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT nIndexFrom, INT nIndexTo) 02056 { 02057 NMTOOLBARW nmtb; 02058 02059 TRACE("index from %d, index to %d\n", nIndexFrom, nIndexTo); 02060 02061 if (nIndexFrom == nIndexTo) 02062 return; 02063 02064 /* MSDN states that iItem is the index of the button, rather than the 02065 * command ID as used by every other NMTOOLBAR notification */ 02066 nmtb.iItem = nIndexFrom; 02067 if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) 02068 { 02069 PCUSTOMBUTTON btnInfo; 02070 NMHDR hdr; 02071 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 02072 int count = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02073 02074 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, nIndexFrom, 0); 02075 02076 SendMessageW(hwndList, LB_DELETESTRING, nIndexFrom, 0); 02077 SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); 02078 SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); 02079 SendMessageW(hwndList, LB_SETCURSEL, nIndexTo, 0); 02080 02081 if (nIndexTo <= 0) 02082 EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), FALSE); 02083 else 02084 EnableWindow(GetDlgItem(hwnd,IDC_MOVEUP_BTN), TRUE); 02085 02086 /* last item is always separator, so -2 instead of -1 */ 02087 if (nIndexTo >= (count - 2)) 02088 EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), FALSE); 02089 else 02090 EnableWindow(GetDlgItem(hwnd,IDC_MOVEDN_BTN), TRUE); 02091 02092 SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, nIndexFrom, 0); 02093 SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); 02094 02095 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 02096 } 02097 } 02098 02099 static void TOOLBAR_Cust_AddButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT nIndexAvail, INT nIndexTo) 02100 { 02101 NMTOOLBARW nmtb; 02102 02103 TRACE("Add: nIndexAvail %d, nIndexTo %d\n", nIndexAvail, nIndexTo); 02104 02105 /* MSDN states that iItem is the index of the button, rather than the 02106 * command ID as used by every other NMTOOLBAR notification */ 02107 nmtb.iItem = nIndexAvail; 02108 if (TOOLBAR_SendNotify(&nmtb.hdr, custInfo->tbInfo, TBN_QUERYINSERT)) 02109 { 02110 PCUSTOMBUTTON btnInfo; 02111 NMHDR hdr; 02112 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 02113 HWND hwndAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 02114 int count = SendMessageW(hwndAvail, LB_GETCOUNT, 0, 0); 02115 02116 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndAvail, LB_GETITEMDATA, nIndexAvail, 0); 02117 02118 if (nIndexAvail != 0) /* index == 0 indicates separator */ 02119 { 02120 /* remove from 'available buttons' list */ 02121 SendMessageW(hwndAvail, LB_DELETESTRING, nIndexAvail, 0); 02122 if (nIndexAvail == count-1) 02123 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail-1 , 0); 02124 else 02125 SendMessageW(hwndAvail, LB_SETCURSEL, nIndexAvail , 0); 02126 } 02127 else 02128 { 02129 PCUSTOMBUTTON btnNew; 02130 02131 /* duplicate 'separator' button */ 02132 btnNew = Alloc(sizeof(CUSTOMBUTTON)); 02133 *btnNew = *btnInfo; 02134 btnInfo = btnNew; 02135 } 02136 02137 /* insert into 'toolbar button' list */ 02138 SendMessageW(hwndList, LB_INSERTSTRING, nIndexTo, 0); 02139 SendMessageW(hwndList, LB_SETITEMDATA, nIndexTo, (LPARAM)btnInfo); 02140 02141 SendMessageW(custInfo->tbHwnd, TB_INSERTBUTTONW, nIndexTo, (LPARAM)&(btnInfo->btn)); 02142 02143 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 02144 } 02145 } 02146 02147 static void TOOLBAR_Cust_RemoveButton(const CUSTDLG_INFO *custInfo, HWND hwnd, INT index) 02148 { 02149 PCUSTOMBUTTON btnInfo; 02150 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 02151 02152 TRACE("Remove: index %d\n", index); 02153 02154 btnInfo = (PCUSTOMBUTTON)SendMessageW(hwndList, LB_GETITEMDATA, index, 0); 02155 02156 /* send TBN_QUERYDELETE notification */ 02157 if (TOOLBAR_IsButtonRemovable(custInfo->tbInfo, index, btnInfo)) 02158 { 02159 NMHDR hdr; 02160 02161 SendMessageW(hwndList, LB_DELETESTRING, index, 0); 02162 SendMessageW(hwndList, LB_SETCURSEL, index , 0); 02163 02164 SendMessageW(custInfo->tbHwnd, TB_DELETEBUTTON, index, 0); 02165 02166 /* insert into 'available button' list */ 02167 if (!(btnInfo->btn.fsStyle & BTNS_SEP)) 02168 TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); 02169 else 02170 Free(btnInfo); 02171 02172 TOOLBAR_SendNotify(&hdr, custInfo->tbInfo, TBN_TOOLBARCHANGE); 02173 } 02174 } 02175 02176 /* drag list notification function for toolbar buttons list box */ 02177 static LRESULT TOOLBAR_Cust_ToolbarDragListNotification(const CUSTDLG_INFO *custInfo, HWND hwnd, 02178 const DRAGLISTINFO *pDLI) 02179 { 02180 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 02181 switch (pDLI->uNotification) 02182 { 02183 case DL_BEGINDRAG: 02184 { 02185 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 02186 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02187 /* no dragging for last item (separator) */ 02188 if (nCurrentItem >= (nCount - 1)) return FALSE; 02189 return TRUE; 02190 } 02191 case DL_DRAGGING: 02192 { 02193 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 02194 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02195 /* no dragging past last item (separator) */ 02196 if ((nCurrentItem >= 0) && (nCurrentItem < (nCount - 1))) 02197 { 02198 DrawInsert(hwnd, hwndList, nCurrentItem); 02199 /* FIXME: native uses "move button" cursor */ 02200 return DL_COPYCURSOR; 02201 } 02202 02203 /* not over toolbar buttons list */ 02204 if (nCurrentItem < 0) 02205 { 02206 POINT ptWindow = pDLI->ptCursor; 02207 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 02208 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 02209 /* over available buttons list? */ 02210 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 02211 /* FIXME: native uses "move button" cursor */ 02212 return DL_COPYCURSOR; 02213 } 02214 /* clear drag arrow */ 02215 DrawInsert(hwnd, hwndList, -1); 02216 return DL_STOPCURSOR; 02217 } 02218 case DL_DROPPED: 02219 { 02220 INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 02221 INT nIndexFrom = SendMessageW(hwndList, LB_GETCURSEL, 0, 0); 02222 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02223 if ((nIndexTo >= 0) && (nIndexTo < (nCount - 1))) 02224 { 02225 /* clear drag arrow */ 02226 DrawInsert(hwnd, hwndList, -1); 02227 /* move item */ 02228 TOOLBAR_Cust_MoveButton(custInfo, hwnd, nIndexFrom, nIndexTo); 02229 } 02230 /* not over toolbar buttons list */ 02231 if (nIndexTo < 0) 02232 { 02233 POINT ptWindow = pDLI->ptCursor; 02234 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 02235 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 02236 /* over available buttons list? */ 02237 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 02238 TOOLBAR_Cust_RemoveButton(custInfo, hwnd, nIndexFrom); 02239 } 02240 break; 02241 } 02242 case DL_CANCELDRAG: 02243 /* Clear drag arrow */ 02244 DrawInsert(hwnd, hwndList, -1); 02245 break; 02246 } 02247 02248 return 0; 02249 } 02250 02251 /* drag list notification function for available buttons list box */ 02252 static LRESULT TOOLBAR_Cust_AvailDragListNotification(const CUSTDLG_INFO *custInfo, HWND hwnd, 02253 const DRAGLISTINFO *pDLI) 02254 { 02255 HWND hwndList = GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX); 02256 switch (pDLI->uNotification) 02257 { 02258 case DL_BEGINDRAG: 02259 return TRUE; 02260 case DL_DRAGGING: 02261 { 02262 INT nCurrentItem = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 02263 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02264 /* no dragging past last item (separator) */ 02265 if ((nCurrentItem >= 0) && (nCurrentItem < nCount)) 02266 { 02267 DrawInsert(hwnd, hwndList, nCurrentItem); 02268 /* FIXME: native uses "move button" cursor */ 02269 return DL_COPYCURSOR; 02270 } 02271 02272 /* not over toolbar buttons list */ 02273 if (nCurrentItem < 0) 02274 { 02275 POINT ptWindow = pDLI->ptCursor; 02276 HWND hwndListAvail = GetDlgItem(hwnd, IDC_AVAILBTN_LBOX); 02277 MapWindowPoints(NULL, hwnd, &ptWindow, 1); 02278 /* over available buttons list? */ 02279 if (ChildWindowFromPoint(hwnd, ptWindow) == hwndListAvail) 02280 /* FIXME: native uses "move button" cursor */ 02281 return DL_COPYCURSOR; 02282 } 02283 /* clear drag arrow */ 02284 DrawInsert(hwnd, hwndList, -1); 02285 return DL_STOPCURSOR; 02286 } 02287 case DL_DROPPED: 02288 { 02289 INT nIndexTo = LBItemFromPt(hwndList, pDLI->ptCursor, TRUE); 02290 INT nCount = SendMessageW(hwndList, LB_GETCOUNT, 0, 0); 02291 INT nIndexFrom = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); 02292 if ((nIndexTo >= 0) && (nIndexTo < nCount)) 02293 { 02294 /* clear drag arrow */ 02295 DrawInsert(hwnd, hwndList, -1); 02296 /* add item */ 02297 TOOLBAR_Cust_AddButton(custInfo, hwnd, nIndexFrom, nIndexTo); 02298 } 02299 } 02300 case DL_CANCELDRAG: 02301 /* Clear drag arrow */ 02302 DrawInsert(hwnd, hwndList, -1); 02303 break; 02304 } 02305 return 0; 02306 } 02307 02308 extern UINT uDragListMessage DECLSPEC_HIDDEN; 02309 02310 /*********************************************************************** 02311 * TOOLBAR_CustomizeDialogProc 02312 * This function implements the toolbar customization dialog. 02313 */ 02314 static INT_PTR CALLBACK 02315 TOOLBAR_CustomizeDialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 02316 { 02317 PCUSTDLG_INFO custInfo = (PCUSTDLG_INFO)GetWindowLongPtrW (hwnd, DWLP_USER); 02318 PCUSTOMBUTTON btnInfo; 02319 NMTOOLBARA nmtb; 02320 TOOLBAR_INFO *infoPtr = custInfo ? custInfo->tbInfo : NULL; 02321 02322 switch (uMsg) 02323 { 02324 case WM_INITDIALOG: 02325 custInfo = (PCUSTDLG_INFO)lParam; 02326 SetWindowLongPtrW (hwnd, DWLP_USER, (LONG_PTR)custInfo); 02327 02328 if (custInfo) 02329 { 02330 WCHAR Buffer[256]; 02331 int i = 0; 02332 int index; 02333 NMTBINITCUSTOMIZE nmtbic; 02334 02335 infoPtr = custInfo->tbInfo; 02336 02337 /* send TBN_QUERYINSERT notification */ 02338 nmtb.iItem = custInfo->tbInfo->nNumButtons; 02339 02340 if (!TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT)) 02341 return FALSE; 02342 02343 nmtbic.hwndDialog = hwnd; 02344 /* Send TBN_INITCUSTOMIZE notification */ 02345 if (TOOLBAR_SendNotify (&nmtbic.hdr, infoPtr, TBN_INITCUSTOMIZE) == 02346 TBNRF_HIDEHELP) 02347 { 02348 TRACE("TBNRF_HIDEHELP requested\n"); 02349 ShowWindow(GetDlgItem(hwnd, IDC_HELP_BTN), SW_HIDE); 02350 } 02351 02352 /* add items to 'toolbar buttons' list and check if removable */ 02353 for (i = 0; i < custInfo->tbInfo->nNumButtons; i++) 02354 { 02355 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 02356 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 02357 btnInfo->btn.fsStyle = BTNS_SEP; 02358 btnInfo->bVirtual = FALSE; 02359 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 02360 02361 /* send TBN_QUERYDELETE notification */ 02362 btnInfo->bRemovable = TOOLBAR_IsButtonRemovable(infoPtr, i, btnInfo); 02363 02364 index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, 0); 02365 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 02366 } 02367 02368 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); 02369 02370 /* insert separator button into 'available buttons' list */ 02371 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 02372 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 02373 btnInfo->btn.fsStyle = BTNS_SEP; 02374 btnInfo->bVirtual = FALSE; 02375 btnInfo->bRemovable = TRUE; 02376 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 02377 index = (int)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); 02378 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 02379 02380 /* insert all buttons into dsa */ 02381 for (i = 0;; i++) 02382 { 02383 /* send TBN_GETBUTTONINFO notification */ 02384 NMTOOLBARW nmtb; 02385 nmtb.iItem = i; 02386 nmtb.pszText = Buffer; 02387 nmtb.cchText = 256; 02388 02389 /* Clear previous button's text */ 02390 ZeroMemory(nmtb.pszText, nmtb.cchText * sizeof(WCHAR)); 02391 02392 if (!TOOLBAR_GetButtonInfo(infoPtr, &nmtb)) 02393 break; 02394 02395 TRACE("WM_INITDIALOG style: %x iItem(%d) idCommand(%d) iString(%ld) %s\n", 02396 nmtb.tbButton.fsStyle, i, 02397 nmtb.tbButton.idCommand, 02398 nmtb.tbButton.iString, 02399 nmtb.tbButton.iString >= 0 ? debugstr_w(infoPtr->strings[nmtb.tbButton.iString]) 02400 : ""); 02401 02402 /* insert button into the apropriate list */ 02403 index = TOOLBAR_GetButtonIndex (custInfo->tbInfo, nmtb.tbButton.idCommand, FALSE); 02404 if (index == -1) 02405 { 02406 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 02407 btnInfo->bVirtual = FALSE; 02408 btnInfo->bRemovable = TRUE; 02409 } 02410 else 02411 { 02412 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, 02413 IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); 02414 } 02415 02416 btnInfo->btn = nmtb.tbButton; 02417 if (!(nmtb.tbButton.fsStyle & BTNS_SEP)) 02418 { 02419 if (lstrlenW(nmtb.pszText)) 02420 lstrcpyW(btnInfo->text, nmtb.pszText); 02421 else if (nmtb.tbButton.iString >= 0 && 02422 nmtb.tbButton.iString < infoPtr->nNumStrings) 02423 { 02424 lstrcpyW(btnInfo->text, 02425 infoPtr->strings[nmtb.tbButton.iString]); 02426 } 02427 } 02428 02429 if (index == -1) 02430 TOOLBAR_Cust_InsertAvailButton(hwnd, btnInfo); 02431 } 02432 02433 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMHEIGHT, 0, infoPtr->nBitmapHeight + 8); 02434 02435 /* select first item in the 'available' list */ 02436 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETCURSEL, 0, 0); 02437 02438 /* append 'virtual' separator button to the 'toolbar buttons' list */ 02439 btnInfo = Alloc(sizeof(CUSTOMBUTTON)); 02440 memset (&btnInfo->btn, 0, sizeof(TBBUTTON)); 02441 btnInfo->btn.fsStyle = BTNS_SEP; 02442 btnInfo->bVirtual = TRUE; 02443 btnInfo->bRemovable = FALSE; 02444 LoadStringW (COMCTL32_hModule, IDS_SEPARATOR, btnInfo->text, 64); 02445 index = (int)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_ADDSTRING, 0, (LPARAM)btnInfo); 02446 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, index, (LPARAM)btnInfo); 02447 02448 /* select last item in the 'toolbar' list */ 02449 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETCURSEL, index, 0); 02450 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETTOPINDEX, index, 0); 02451 02452 MakeDragList(GetDlgItem(hwnd, IDC_TOOLBARBTN_LBOX)); 02453 MakeDragList(GetDlgItem(hwnd, IDC_AVAILBTN_LBOX)); 02454 02455 /* set focus and disable buttons */ 02456 PostMessageW (hwnd, WM_USER, 0, 0); 02457 } 02458 return TRUE; 02459 02460 case WM_USER: 02461 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 02462 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 02463 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), FALSE); 02464 SetFocus (GetDlgItem (hwnd, IDC_TOOLBARBTN_LBOX)); 02465 return TRUE; 02466 02467 case WM_CLOSE: 02468 EndDialog(hwnd, FALSE); 02469 return TRUE; 02470 02471 case WM_COMMAND: 02472 switch (LOWORD(wParam)) 02473 { 02474 case IDC_TOOLBARBTN_LBOX: 02475 if (HIWORD(wParam) == LBN_SELCHANGE) 02476 { 02477 PCUSTOMBUTTON btnInfo; 02478 NMTOOLBARA nmtb; 02479 int count; 02480 int index; 02481 02482 count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); 02483 index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 02484 02485 /* send TBN_QUERYINSERT notification */ 02486 nmtb.iItem = index; 02487 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYINSERT); 02488 02489 /* get list box item */ 02490 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, index, 0); 02491 02492 if (index == (count - 1)) 02493 { 02494 /* last item (virtual separator) */ 02495 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 02496 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 02497 } 02498 else if (index == (count - 2)) 02499 { 02500 /* second last item (last non-virtual item) */ 02501 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); 02502 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), FALSE); 02503 } 02504 else if (index == 0) 02505 { 02506 /* first item */ 02507 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), FALSE); 02508 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); 02509 } 02510 else 02511 { 02512 EnableWindow (GetDlgItem (hwnd,IDC_MOVEUP_BTN), TRUE); 02513 EnableWindow (GetDlgItem (hwnd,IDC_MOVEDN_BTN), TRUE); 02514 } 02515 02516 EnableWindow (GetDlgItem (hwnd,IDC_REMOVE_BTN), btnInfo->bRemovable); 02517 } 02518 break; 02519 02520 case IDC_MOVEUP_BTN: 02521 { 02522 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 02523 TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index-1); 02524 } 02525 break; 02526 02527 case IDC_MOVEDN_BTN: /* move down */ 02528 { 02529 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 02530 TOOLBAR_Cust_MoveButton(custInfo, hwnd, index, index+1); 02531 } 02532 break; 02533 02534 case IDC_REMOVE_BTN: /* remove button */ 02535 { 02536 int index = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 02537 02538 if (LB_ERR == index) 02539 break; 02540 02541 TOOLBAR_Cust_RemoveButton(custInfo, hwnd, index); 02542 } 02543 break; 02544 case IDC_HELP_BTN: 02545 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_CUSTHELP); 02546 break; 02547 case IDC_RESET_BTN: 02548 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_RESET); 02549 break; 02550 02551 case IDOK: /* Add button */ 02552 { 02553 int index; 02554 int indexto; 02555 02556 index = SendDlgItemMessageW(hwnd, IDC_AVAILBTN_LBOX, LB_GETCURSEL, 0, 0); 02557 indexto = SendDlgItemMessageW(hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCURSEL, 0, 0); 02558 02559 TOOLBAR_Cust_AddButton(custInfo, hwnd, index, indexto); 02560 } 02561 break; 02562 02563 case IDCANCEL: 02564 EndDialog(hwnd, FALSE); 02565 break; 02566 } 02567 return TRUE; 02568 02569 case WM_DESTROY: 02570 { 02571 int count; 02572 int i; 02573 02574 /* delete items from 'toolbar buttons' listbox*/ 02575 count = SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETCOUNT, 0, 0); 02576 for (i = 0; i < count; i++) 02577 { 02578 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_GETITEMDATA, i, 0); 02579 Free(btnInfo); 02580 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_SETITEMDATA, 0, 0); 02581 } 02582 SendDlgItemMessageW (hwnd, IDC_TOOLBARBTN_LBOX, LB_RESETCONTENT, 0, 0); 02583 02584 02585 /* delete items from 'available buttons' listbox*/ 02586 count = SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETCOUNT, 0, 0); 02587 for (i = 0; i < count; i++) 02588 { 02589 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_GETITEMDATA, i, 0); 02590 Free(btnInfo); 02591 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_SETITEMDATA, i, 0); 02592 } 02593 SendDlgItemMessageW (hwnd, IDC_AVAILBTN_LBOX, LB_RESETCONTENT, 0, 0); 02594 } 02595 return TRUE; 02596 02597 case WM_DRAWITEM: 02598 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) 02599 { 02600 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; 02601 RECT rcButton; 02602 RECT rcText; 02603 HPEN hPen, hOldPen; 02604 HBRUSH hOldBrush; 02605 COLORREF oldText = 0; 02606 COLORREF oldBk = 0; 02607 02608 /* get item data */ 02609 btnInfo = (PCUSTOMBUTTON)SendDlgItemMessageW (hwnd, wParam, LB_GETITEMDATA, lpdis->itemID, 0); 02610 if (btnInfo == NULL) 02611 { 02612 FIXME("btnInfo invalid!\n"); 02613 return TRUE; 02614 } 02615 02616 /* set colors and select objects */ 02617 oldBk = SetBkColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlight:comctl32_color.clrWindow); 02618 if (btnInfo->bVirtual) 02619 oldText = SetTextColor (lpdis->hDC, comctl32_color.clrGrayText); 02620 else 02621 oldText = SetTextColor (lpdis->hDC, (lpdis->itemState & ODS_FOCUS)?comctl32_color.clrHighlightText:comctl32_color.clrWindowText); 02622 hPen = CreatePen( PS_SOLID, 1, 02623 (lpdis->itemState & ODS_SELECTED)?comctl32_color.clrHighlight:comctl32_color.clrWindow); 02624 hOldPen = SelectObject (lpdis->hDC, hPen ); 02625 hOldBrush = SelectObject (lpdis->hDC, GetSysColorBrush ((lpdis->itemState & ODS_FOCUS)?COLOR_HIGHLIGHT:COLOR_WINDOW)); 02626 02627 /* fill background rectangle */ 02628 Rectangle (lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top, 02629 lpdis->rcItem.right, lpdis->rcItem.bottom); 02630 02631 /* calculate button and text rectangles */ 02632 CopyRect (&rcButton, &lpdis->rcItem); 02633 InflateRect (&rcButton, -1, -1); 02634 CopyRect (&rcText, &rcButton); 02635 rcButton.right = rcButton.left + custInfo->tbInfo->nBitmapWidth + 6; 02636 rcText.left = rcButton.right + 2; 02637 02638 /* draw focus rectangle */ 02639 if (lpdis->itemState & ODS_FOCUS) 02640 DrawFocusRect (lpdis->hDC, &lpdis->rcItem); 02641 02642 /* draw button */ 02643 if (!(infoPtr->dwStyle & TBSTYLE_FLAT)) 02644 DrawEdge (lpdis->hDC, &rcButton, EDGE_RAISED, BF_RECT|BF_MIDDLE|BF_SOFT); 02645 02646 /* draw image and text */ 02647 if ((btnInfo->btn.fsStyle & BTNS_SEP) == 0) { 02648 HIMAGELIST himl = GETDEFIMAGELIST(infoPtr, GETHIMLID(infoPtr, 02649 btnInfo->btn.iBitmap)); 02650 ImageList_Draw (himl, GETIBITMAP(infoPtr, btnInfo->btn.iBitmap), 02651 lpdis->hDC, rcButton.left+3, rcButton.top+3, ILD_NORMAL); 02652 } 02653 DrawTextW (lpdis->hDC, btnInfo->text, -1, &rcText, 02654 DT_LEFT | DT_VCENTER | DT_SINGLELINE); 02655 02656 /* delete objects and reset colors */ 02657 SelectObject (lpdis->hDC, hOldBrush); 02658 SelectObject (lpdis->hDC, hOldPen); 02659 SetBkColor (lpdis->hDC, oldBk); 02660 SetTextColor (lpdis->hDC, oldText); 02661 DeleteObject( hPen ); 02662 return TRUE; 02663 } 02664 return FALSE; 02665 02666 case WM_MEASUREITEM: 02667 if (wParam == IDC_AVAILBTN_LBOX || wParam == IDC_TOOLBARBTN_LBOX) 02668 { 02669 MEASUREITEMSTRUCT *lpmis = (MEASUREITEMSTRUCT*)lParam; 02670 02671 lpmis->itemHeight = 15 + 8; /* default height */ 02672 02673 return TRUE; 02674 } 02675 return FALSE; 02676 02677 default: 02678 if (uDragListMessage && (uMsg == uDragListMessage)) 02679 { 02680 if (wParam == IDC_TOOLBARBTN_LBOX) 02681 { 02682 LRESULT res = TOOLBAR_Cust_ToolbarDragListNotification( 02683 custInfo, hwnd, (DRAGLISTINFO *)lParam); 02684 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); 02685 return TRUE; 02686 } 02687 else if (wParam == IDC_AVAILBTN_LBOX) 02688 { 02689 LRESULT res = TOOLBAR_Cust_AvailDragListNotification( 02690 custInfo, hwnd, (DRAGLISTINFO *)lParam); 02691 SetWindowLongPtrW(hwnd, DWLP_MSGRESULT, res); 02692 return TRUE; 02693 } 02694 } 02695 return FALSE; 02696 } 02697 } 02698 02699 static BOOL 02700 TOOLBAR_AddBitmapToImageList(TOOLBAR_INFO *infoPtr, HIMAGELIST himlDef, const TBITMAP_INFO *bitmap) 02701 { 02702 HBITMAP hbmLoad; 02703 INT nCountBefore = ImageList_GetImageCount(himlDef); 02704 INT nCountAfter; 02705 INT cxIcon, cyIcon; 02706 INT nAdded; 02707 INT nIndex; 02708 02709 TRACE("adding hInst=%p nID=%d nButtons=%d\n", bitmap->hInst, bitmap->nID, bitmap->nButtons); 02710 /* Add bitmaps to the default image list */ 02711 if (bitmap->hInst == NULL) /* a handle was passed */ 02712 hbmLoad = CopyImage(ULongToHandle(bitmap->nID), IMAGE_BITMAP, 0, 0, 0); 02713 else if (bitmap->hInst == COMCTL32_hModule) 02714 hbmLoad = LoadImageW( bitmap->hInst, MAKEINTRESOURCEW(bitmap->nID), 02715 IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION ); 02716 else 02717 hbmLoad = CreateMappedBitmap(bitmap->hInst, bitmap->nID, 0, NULL, 0); 02718 02719 /* enlarge the bitmap if needed */ 02720 ImageList_GetIconSize(himlDef, &cxIcon, &cyIcon); 02721 if (bitmap->hInst != COMCTL32_hModule) 02722 COMCTL32_EnsureBitmapSize(&hbmLoad, cxIcon*(INT)bitmap->nButtons, cyIcon, comctl32_color.clrBtnFace); 02723 02724 nIndex = ImageList_AddMasked(himlDef, hbmLoad, comctl32_color.clrBtnFace); 02725 DeleteObject(hbmLoad); 02726 if (nIndex == -1) 02727 return FALSE; 02728 02729 nCountAfter = ImageList_GetImageCount(himlDef); 02730 nAdded = nCountAfter - nCountBefore; 02731 if (bitmap->nButtons == 0) /* wParam == 0 is special and means add only one image */ 02732 { 02733 ImageList_SetImageCount(himlDef, nCountBefore + 1); 02734 } else if (nAdded > (INT)bitmap->nButtons) { 02735 TRACE("Added more images than wParam: Previous image number %i added %i while wParam %i. Images in list %i\n", 02736 nCountBefore, nAdded, bitmap->nButtons, nCountAfter); 02737 } 02738 02739 infoPtr->nNumBitmaps += nAdded; 02740 return TRUE; 02741 } 02742 02743 static void 02744 TOOLBAR_CheckImageListIconSize(TOOLBAR_INFO *infoPtr) 02745 { 02746 HIMAGELIST himlDef; 02747 HIMAGELIST himlNew; 02748 INT cx, cy; 02749 INT i; 02750 02751 himlDef = GETDEFIMAGELIST(infoPtr, 0); 02752 if (himlDef == NULL || himlDef != infoPtr->himlInt) 02753 return; 02754 if (!ImageList_GetIconSize(himlDef, &cx, &cy)) 02755 return; 02756 if (cx == infoPtr->nBitmapWidth && cy == infoPtr->nBitmapHeight) 02757 return; 02758 02759 TRACE("Update icon size: %dx%d -> %dx%d\n", 02760 cx, cy, infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 02761 02762 himlNew = ImageList_Create(infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, 02763 ILC_COLOR32|ILC_MASK, 8, 2); 02764 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) 02765 TOOLBAR_AddBitmapToImageList(infoPtr, himlNew, &infoPtr->bitmaps[i]); 02766 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlNew, 0); 02767 infoPtr->himlInt = himlNew; 02768 02769 infoPtr->nNumBitmaps -= ImageList_GetImageCount(himlDef); 02770 ImageList_Destroy(himlDef); 02771 } 02772 02773 /*********************************************************************** 02774 * TOOLBAR_AddBitmap: Add the bitmaps to the default image list. 02775 * 02776 */ 02777 static LRESULT 02778 TOOLBAR_AddBitmap (TOOLBAR_INFO *infoPtr, INT count, const TBADDBITMAP *lpAddBmp) 02779 { 02780 TBITMAP_INFO info; 02781 INT iSumButtons, i; 02782 HIMAGELIST himlDef; 02783 02784 TRACE("hwnd=%p count=%d lpAddBmp=%p\n", infoPtr->hwndSelf, count, lpAddBmp); 02785 if (!lpAddBmp) 02786 return -1; 02787 02788 if (lpAddBmp->hInst == HINST_COMMCTRL) 02789 { 02790 info.hInst = COMCTL32_hModule; 02791 switch (lpAddBmp->nID) 02792 { 02793 case IDB_STD_SMALL_COLOR: 02794 info.nButtons = 15; 02795 info.nID = IDB_STD_SMALL; 02796 break; 02797 case IDB_STD_LARGE_COLOR: 02798 info.nButtons = 15; 02799 info.nID = IDB_STD_LARGE; 02800 break; 02801 case IDB_VIEW_SMALL_COLOR: 02802 info.nButtons = 12; 02803 info.nID = IDB_VIEW_SMALL; 02804 break; 02805 case IDB_VIEW_LARGE_COLOR: 02806 info.nButtons = 12; 02807 info.nID = IDB_VIEW_LARGE; 02808 break; 02809 case IDB_HIST_SMALL_COLOR: 02810 info.nButtons = 5; 02811 info.nID = IDB_HIST_SMALL; 02812 break; 02813 case IDB_HIST_LARGE_COLOR: 02814 info.nButtons = 5; 02815 info.nID = IDB_HIST_LARGE; 02816 break; 02817 default: 02818 return -1; 02819 } 02820 02821 TRACE ("adding %d internal bitmaps!\n", info.nButtons); 02822 02823 /* Windows resize all the buttons to the size of a newly added standard image */ 02824 if (lpAddBmp->nID & 1) 02825 { 02826 /* large icons: 24x24. Will make the button 31x30 */ 02827 SendMessageW (infoPtr->hwndSelf, TB_SETBITMAPSIZE, 0, MAKELPARAM(24, 24)); 02828 } 02829 else 02830 { 02831 /* small icons: 16x16. Will make the buttons 23x22 */ 02832 SendMessageW (infoPtr->hwndSelf, TB_SETBITMAPSIZE, 0, MAKELPARAM(16, 16)); 02833 } 02834 02835 TOOLBAR_CalcToolbar (infoPtr); 02836 } 02837 else 02838 { 02839 info.nButtons = count; 02840 info.hInst = lpAddBmp->hInst; 02841 info.nID = lpAddBmp->nID; 02842 TRACE("adding %d bitmaps!\n", info.nButtons); 02843 } 02844 02845 /* check if the bitmap is already loaded and compute iSumButtons */ 02846 iSumButtons = 0; 02847 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) 02848 { 02849 if (infoPtr->bitmaps[i].hInst == info.hInst && 02850 infoPtr->bitmaps[i].nID == info.nID) 02851 return iSumButtons; 02852 iSumButtons += infoPtr->bitmaps[i].nButtons; 02853 } 02854 02855 if (!infoPtr->cimlDef) { 02856 /* create new default image list */ 02857 TRACE ("creating default image list!\n"); 02858 02859 himlDef = ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, 02860 ILC_COLOR32 | ILC_MASK, info.nButtons, 2); 02861 TOOLBAR_InsertImageList(&infoPtr->himlDef, &infoPtr->cimlDef, himlDef, 0); 02862 infoPtr->himlInt = himlDef; 02863 } 02864 else { 02865 himlDef = GETDEFIMAGELIST(infoPtr, 0); 02866 } 02867 02868 if (!himlDef) { 02869 WARN("No default image list available\n"); 02870 return -1; 02871 } 02872 02873 if (!TOOLBAR_AddBitmapToImageList(infoPtr, himlDef, &info)) 02874 return -1; 02875 02876 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); 02877 infoPtr->bitmaps = ReAlloc(infoPtr->bitmaps, (infoPtr->nNumBitmapInfos + 1) * sizeof(TBITMAP_INFO)); 02878 infoPtr->bitmaps[infoPtr->nNumBitmapInfos] = info; 02879 infoPtr->nNumBitmapInfos++; 02880 TRACE("Number of bitmap infos: %d\n", infoPtr->nNumBitmapInfos); 02881 02882 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 02883 return iSumButtons; 02884 } 02885 02886 02887 static LRESULT 02888 TOOLBAR_AddButtonsT(TOOLBAR_INFO *infoPtr, INT nAddButtons, const TBBUTTON* lpTbb, BOOL fUnicode) 02889 { 02890 TRACE("adding %d buttons (unicode=%d)!\n", nAddButtons, fUnicode); 02891 02892 return TOOLBAR_InternalInsertButtonsT(infoPtr, -1, nAddButtons, lpTbb, fUnicode); 02893 } 02894 02895 02896 static LRESULT 02897 TOOLBAR_AddStringW (TOOLBAR_INFO *infoPtr, HINSTANCE hInstance, LPARAM lParam) 02898 { 02899 #define MAX_RESOURCE_STRING_LENGTH 512 02900 BOOL fFirstString = (infoPtr->nNumStrings == 0); 02901 INT nIndex = infoPtr->nNumStrings; 02902 02903 TRACE("%p, %lx\n", hInstance, lParam); 02904 02905 if (IS_INTRESOURCE(lParam)) { 02906 WCHAR szString[MAX_RESOURCE_STRING_LENGTH]; 02907 WCHAR delimiter; 02908 WCHAR *next_delim; 02909 HRSRC hrsrc; 02910 WCHAR *p; 02911 INT len; 02912 02913 TRACE("adding string from resource\n"); 02914 02915 if (!hInstance) return -1; 02916 02917 hrsrc = FindResourceW( hInstance, MAKEINTRESOURCEW((LOWORD(lParam) >> 4) + 1), 02918 (LPWSTR)RT_STRING ); 02919 if (!hrsrc) 02920 { 02921 TRACE("string not found in resources\n"); 02922 return -1; 02923 } 02924 02925 len = LoadStringW (hInstance, (UINT)lParam, 02926 szString, MAX_RESOURCE_STRING_LENGTH); 02927 02928 TRACE("len=%d %s\n", len, debugstr_w(szString)); 02929 if (len == 0 || len == 1) 02930 return nIndex; 02931 02932 TRACE("delimiter: 0x%x\n", *szString); 02933 delimiter = *szString; 02934 p = szString + 1; 02935 02936 while ((next_delim = strchrW(p, delimiter)) != NULL) { 02937 *next_delim = 0; 02938 if (next_delim + 1 >= szString + len) 02939 { 02940 /* this may happen if delimiter == '\0' or if the last char is a 02941 * delimiter (then it is ignored like the native does) */ 02942 break; 02943 } 02944 02945 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 02946 Str_SetPtrW(&infoPtr->strings[infoPtr->nNumStrings], p); 02947 infoPtr->nNumStrings++; 02948 02949 p = next_delim + 1; 02950 } 02951 } 02952 else { 02953 LPWSTR p = (LPWSTR)lParam; 02954 INT len; 02955 02956 if (p == NULL) 02957 return -1; 02958 TRACE("adding string(s) from array\n"); 02959 while (*p) { 02960 len = strlenW (p); 02961 02962 TRACE("len=%d %s\n", len, debugstr_w(p)); 02963 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 02964 Str_SetPtrW (&infoPtr->strings[infoPtr->nNumStrings], p); 02965 infoPtr->nNumStrings++; 02966 02967 p += (len+1); 02968 } 02969 } 02970 02971 if (fFirstString) 02972 TOOLBAR_CalcToolbar(infoPtr); 02973 return nIndex; 02974 } 02975 02976 02977 static LRESULT 02978 TOOLBAR_AddStringA (TOOLBAR_INFO *infoPtr, HINSTANCE hInstance, LPARAM lParam) 02979 { 02980 BOOL fFirstString = (infoPtr->nNumStrings == 0); 02981 LPSTR p; 02982 INT nIndex; 02983 INT len; 02984 02985 TRACE("%p, %lx\n", hInstance, lParam); 02986 02987 if (IS_INTRESOURCE(lParam)) /* load from resources */ 02988 return TOOLBAR_AddStringW(infoPtr, hInstance, lParam); 02989 02990 p = (LPSTR)lParam; 02991 if (p == NULL) 02992 return -1; 02993 02994 TRACE("adding string(s) from array\n"); 02995 nIndex = infoPtr->nNumStrings; 02996 while (*p) { 02997 len = strlen (p); 02998 TRACE("len=%d \"%s\"\n", len, p); 02999 03000 infoPtr->strings = ReAlloc(infoPtr->strings, sizeof(LPWSTR)*(infoPtr->nNumStrings+1)); 03001 Str_SetPtrAtoW(&infoPtr->strings[infoPtr->nNumStrings], p); 03002 infoPtr->nNumStrings++; 03003 03004 p += (len+1); 03005 } 03006 03007 if (fFirstString) 03008 TOOLBAR_CalcToolbar(infoPtr); 03009 return nIndex; 03010 } 03011 03012 03013 static LRESULT 03014 TOOLBAR_AutoSize (TOOLBAR_INFO *infoPtr) 03015 { 03016 RECT parent_rect; 03017 HWND parent; 03018 INT x, y; 03019 INT cx, cy; 03020 03021 TRACE("auto sizing, style=%x!\n", infoPtr->dwStyle); 03022 03023 parent = GetParent (infoPtr->hwndSelf); 03024 03025 if (!parent || !infoPtr->bDoRedraw) 03026 return 0; 03027 03028 GetClientRect(parent, &parent_rect); 03029 03030 x = parent_rect.left; 03031 y = parent_rect.top; 03032 03033 TRACE("nRows: %d, infoPtr->nButtonHeight: %d\n", infoPtr->nRows, infoPtr->nButtonHeight); 03034 03035 cy = TOP_BORDER + infoPtr->nRows * infoPtr->nButtonHeight + BOTTOM_BORDER; 03036 cx = parent_rect.right - parent_rect.left; 03037 03038 if ((infoPtr->dwStyle & TBSTYLE_WRAPABLE) || (infoPtr->dwExStyle & TBSTYLE_EX_UNDOC1)) 03039 { 03040 TOOLBAR_LayoutToolbar(infoPtr); 03041 InvalidateRect( infoPtr->hwndSelf, NULL, TRUE ); 03042 } 03043 03044 if (!(infoPtr->dwStyle & CCS_NORESIZE)) 03045 { 03046 RECT window_rect; 03047 UINT uPosFlags = SWP_NOZORDER | SWP_NOACTIVATE; 03048 03049 if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_NOMOVEY) 03050 { 03051 GetWindowRect(infoPtr->hwndSelf, &window_rect); 03052 MapWindowPoints( 0, parent, (POINT *)&window_rect, 2 ); 03053 y = window_rect.top; 03054 } 03055 if ((infoPtr->dwStyle & CCS_BOTTOM) == CCS_BOTTOM) 03056 { 03057 GetWindowRect(infoPtr->hwndSelf, &window_rect); 03058 y = parent_rect.bottom - ( window_rect.bottom - window_rect.top); 03059 } 03060 03061 if (infoPtr->dwStyle & CCS_NOPARENTALIGN) 03062 uPosFlags |= SWP_NOMOVE; 03063 03064 if (!(infoPtr->dwStyle & CCS_NODIVIDER)) 03065 cy += GetSystemMetrics(SM_CYEDGE); 03066 03067 if (infoPtr->dwStyle & WS_BORDER) 03068 { 03069 cx += 2 * GetSystemMetrics(SM_CXBORDER); 03070 cy += 2 * GetSystemMetrics(SM_CYBORDER); 03071 } 03072 03073 SetWindowPos(infoPtr->hwndSelf, NULL, x, y, cx, cy, uPosFlags); 03074 } 03075 03076 return 0; 03077 } 03078 03079 03080 static inline LRESULT 03081 TOOLBAR_ButtonCount (const TOOLBAR_INFO *infoPtr) 03082 { 03083 return infoPtr->nNumButtons; 03084 } 03085 03086 03087 static inline LRESULT 03088 TOOLBAR_ButtonStructSize (TOOLBAR_INFO *infoPtr, DWORD Size) 03089 { 03090 infoPtr->dwStructSize = Size; 03091 03092 return 0; 03093 } 03094 03095 03096 static LRESULT 03097 TOOLBAR_ChangeBitmap (TOOLBAR_INFO *infoPtr, INT Id, INT Index) 03098 { 03099 TBUTTON_INFO *btnPtr; 03100 INT nIndex; 03101 03102 TRACE("button %d, iBitmap now %d\n", Id, Index); 03103 03104 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03105 if (nIndex == -1) 03106 return FALSE; 03107 03108 btnPtr = &infoPtr->buttons[nIndex]; 03109 btnPtr->iBitmap = Index; 03110 03111 /* we HAVE to erase the background, the new bitmap could be */ 03112 /* transparent */ 03113 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03114 03115 return TRUE; 03116 } 03117 03118 03119 static LRESULT 03120 TOOLBAR_CheckButton (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 03121 { 03122 TBUTTON_INFO *btnPtr; 03123 INT nIndex; 03124 INT nOldIndex = -1; 03125 BOOL bChecked = FALSE; 03126 03127 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03128 03129 TRACE("hwnd=%p, btn index=%d, lParam=0x%08lx\n", infoPtr->hwndSelf, nIndex, lParam); 03130 03131 if (nIndex == -1) 03132 return FALSE; 03133 03134 btnPtr = &infoPtr->buttons[nIndex]; 03135 03136 bChecked = (btnPtr->fsState & TBSTATE_CHECKED) ? TRUE : FALSE; 03137 03138 if (LOWORD(lParam) == FALSE) 03139 btnPtr->fsState &= ~TBSTATE_CHECKED; 03140 else { 03141 if (btnPtr->fsStyle & BTNS_GROUP) { 03142 nOldIndex = 03143 TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, nIndex); 03144 if (nOldIndex == nIndex) 03145 return 0; 03146 if (nOldIndex != -1) 03147 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; 03148 } 03149 btnPtr->fsState |= TBSTATE_CHECKED; 03150 } 03151 03152 if( bChecked != LOWORD(lParam) ) 03153 { 03154 if (nOldIndex != -1) 03155 InvalidateRect(infoPtr->hwndSelf, &infoPtr->buttons[nOldIndex].rect, TRUE); 03156 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03157 } 03158 03159 /* FIXME: Send a WM_NOTIFY?? */ 03160 03161 return TRUE; 03162 } 03163 03164 03165 static LRESULT 03166 TOOLBAR_CommandToIndex (const TOOLBAR_INFO *infoPtr, INT Id) 03167 { 03168 return TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03169 } 03170 03171 03172 static LRESULT 03173 TOOLBAR_Customize (TOOLBAR_INFO *infoPtr) 03174 { 03175 CUSTDLG_INFO custInfo; 03176 LRESULT ret; 03177 NMHDR nmhdr; 03178 03179 custInfo.tbInfo = infoPtr; 03180 custInfo.tbHwnd = infoPtr->hwndSelf; 03181 03182 /* send TBN_BEGINADJUST notification */ 03183 TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_BEGINADJUST); 03184 03185 ret = DialogBoxParamW (COMCTL32_hModule, MAKEINTRESOURCEW(IDD_TBCUSTOMIZE), 03186 infoPtr->hwndSelf, TOOLBAR_CustomizeDialogProc, (LPARAM)&custInfo); 03187 03188 /* send TBN_ENDADJUST notification */ 03189 TOOLBAR_SendNotify (&nmhdr, infoPtr, TBN_ENDADJUST); 03190 03191 return ret; 03192 } 03193 03194 03195 static LRESULT 03196 TOOLBAR_DeleteButton (TOOLBAR_INFO *infoPtr, INT nIndex) 03197 { 03198 NMTOOLBARW nmtb; 03199 TBUTTON_INFO *btnPtr = &infoPtr->buttons[nIndex]; 03200 03201 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 03202 return FALSE; 03203 03204 memset(&nmtb, 0, sizeof(nmtb)); 03205 nmtb.iItem = btnPtr->idCommand; 03206 nmtb.tbButton.iBitmap = btnPtr->iBitmap; 03207 nmtb.tbButton.idCommand = btnPtr->idCommand; 03208 nmtb.tbButton.fsState = btnPtr->fsState; 03209 nmtb.tbButton.fsStyle = btnPtr->fsStyle; 03210 nmtb.tbButton.dwData = btnPtr->dwData; 03211 nmtb.tbButton.iString = btnPtr->iString; 03212 TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_DELETINGBUTTON); 03213 03214 TOOLBAR_TooltipDelTool(infoPtr, &infoPtr->buttons[nIndex]); 03215 03216 if (infoPtr->nNumButtons == 1) { 03217 TRACE(" simple delete!\n"); 03218 if (TOOLBAR_ButtonHasString(infoPtr->buttons)) 03219 Free((LPWSTR)infoPtr->buttons[0].iString); 03220 Free (infoPtr->buttons); 03221 infoPtr->buttons = NULL; 03222 infoPtr->nNumButtons = 0; 03223 } 03224 else { 03225 TBUTTON_INFO *oldButtons = infoPtr->buttons; 03226 TRACE("complex delete! [nIndex=%d]\n", nIndex); 03227 03228 infoPtr->nNumButtons--; 03229 infoPtr->buttons = Alloc (sizeof (TBUTTON_INFO) * infoPtr->nNumButtons); 03230 if (nIndex > 0) { 03231 memcpy (&infoPtr->buttons[0], &oldButtons[0], 03232 nIndex * sizeof(TBUTTON_INFO)); 03233 } 03234 03235 if (nIndex < infoPtr->nNumButtons) { 03236 memcpy (&infoPtr->buttons[nIndex], &oldButtons[nIndex+1], 03237 (infoPtr->nNumButtons - nIndex) * sizeof(TBUTTON_INFO)); 03238 } 03239 03240 if (TOOLBAR_ButtonHasString(&oldButtons[nIndex])) 03241 Free((LPWSTR)oldButtons[nIndex].iString); 03242 Free (oldButtons); 03243 } 03244 03245 TOOLBAR_LayoutToolbar(infoPtr); 03246 03247 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 03248 03249 return TRUE; 03250 } 03251 03252 03253 static LRESULT 03254 TOOLBAR_EnableButton (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 03255 { 03256 TBUTTON_INFO *btnPtr; 03257 INT nIndex; 03258 DWORD bState; 03259 03260 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03261 03262 TRACE("hwnd=%p, btn id=%d, lParam=0x%08lx\n", infoPtr->hwndSelf, Id, lParam); 03263 03264 if (nIndex == -1) 03265 return FALSE; 03266 03267 btnPtr = &infoPtr->buttons[nIndex]; 03268 03269 bState = btnPtr->fsState & TBSTATE_ENABLED; 03270 03271 /* update the toolbar button state */ 03272 if(LOWORD(lParam) == FALSE) { 03273 btnPtr->fsState &= ~(TBSTATE_ENABLED | TBSTATE_PRESSED); 03274 } else { 03275 btnPtr->fsState |= TBSTATE_ENABLED; 03276 } 03277 03278 /* redraw the button only if the state of the button changed */ 03279 if(bState != (btnPtr->fsState & TBSTATE_ENABLED)) 03280 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03281 03282 return TRUE; 03283 } 03284 03285 03286 static inline LRESULT 03287 TOOLBAR_GetAnchorHighlight (const TOOLBAR_INFO *infoPtr) 03288 { 03289 return infoPtr->bAnchor; 03290 } 03291 03292 03293 static LRESULT 03294 TOOLBAR_GetBitmap (const TOOLBAR_INFO *infoPtr, INT Id) 03295 { 03296 INT nIndex; 03297 03298 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03299 if (nIndex == -1) 03300 return -1; 03301 03302 return infoPtr->buttons[nIndex].iBitmap; 03303 } 03304 03305 03306 static inline LRESULT 03307 TOOLBAR_GetBitmapFlags (void) 03308 { 03309 return (GetDeviceCaps (0, LOGPIXELSX) >= 120) ? TBBF_LARGE : 0; 03310 } 03311 03312 03313 static LRESULT 03314 TOOLBAR_GetButton (const TOOLBAR_INFO *infoPtr, INT nIndex, TBBUTTON *lpTbb) 03315 { 03316 TBUTTON_INFO *btnPtr; 03317 03318 if (lpTbb == NULL) 03319 return FALSE; 03320 03321 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 03322 return FALSE; 03323 03324 btnPtr = &infoPtr->buttons[nIndex]; 03325 lpTbb->iBitmap = btnPtr->iBitmap; 03326 lpTbb->idCommand = btnPtr->idCommand; 03327 lpTbb->fsState = btnPtr->fsState; 03328 lpTbb->fsStyle = btnPtr->fsStyle; 03329 lpTbb->bReserved[0] = 0; 03330 lpTbb->bReserved[1] = 0; 03331 lpTbb->dwData = btnPtr->dwData; 03332 lpTbb->iString = btnPtr->iString; 03333 03334 return TRUE; 03335 } 03336 03337 03338 static LRESULT 03339 TOOLBAR_GetButtonInfoT(const TOOLBAR_INFO *infoPtr, INT Id, LPTBBUTTONINFOW lpTbInfo, BOOL bUnicode) 03340 { 03341 /* TBBUTTONINFOW and TBBUTTONINFOA have the same layout*/ 03342 TBUTTON_INFO *btnPtr; 03343 INT nIndex; 03344 03345 if (lpTbInfo == NULL) 03346 return -1; 03347 03348 /* MSDN documents a iImageLabel field added in Vista but it is not present in 03349 * the headers and tests shows that even with comctl 6 Vista accepts only the 03350 * original TBBUTTONINFO size 03351 */ 03352 if (lpTbInfo->cbSize != sizeof(TBBUTTONINFOW)) 03353 { 03354 WARN("Invalid button size\n"); 03355 return -1; 03356 } 03357 03358 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, lpTbInfo->dwMask & TBIF_BYINDEX); 03359 if (nIndex == -1) 03360 return -1; 03361 03362 if (!(btnPtr = &infoPtr->buttons[nIndex])) return -1; 03363 03364 if (lpTbInfo->dwMask & TBIF_COMMAND) 03365 lpTbInfo->idCommand = btnPtr->idCommand; 03366 if (lpTbInfo->dwMask & TBIF_IMAGE) 03367 lpTbInfo->iImage = btnPtr->iBitmap; 03368 if (lpTbInfo->dwMask & TBIF_LPARAM) 03369 lpTbInfo->lParam = btnPtr->dwData; 03370 if (lpTbInfo->dwMask & TBIF_SIZE) 03371 /* tests show that for separators TBIF_SIZE returns not calculated width, 03372 but cx property, that differs from 0 only if application have 03373 specifically set it */ 03374 lpTbInfo->cx = (btnPtr->fsStyle & BTNS_SEP) 03375 ? btnPtr->cx : (WORD)(btnPtr->rect.right - btnPtr->rect.left); 03376 if (lpTbInfo->dwMask & TBIF_STATE) 03377 lpTbInfo->fsState = btnPtr->fsState; 03378 if (lpTbInfo->dwMask & TBIF_STYLE) 03379 lpTbInfo->fsStyle = btnPtr->fsStyle; 03380 if (lpTbInfo->dwMask & TBIF_TEXT) { 03381 /* TB_GETBUTTONINFO doesn't retrieve text from the string list, so we 03382 can't use TOOLBAR_GetText here */ 03383 if (!IS_INTRESOURCE(btnPtr->iString) && (btnPtr->iString != -1)) { 03384 LPWSTR lpText = (LPWSTR)btnPtr->iString; 03385 if (bUnicode) 03386 Str_GetPtrW(lpText, lpTbInfo->pszText, lpTbInfo->cchText); 03387 else 03388 Str_GetPtrWtoA(lpText, (LPSTR)lpTbInfo->pszText, lpTbInfo->cchText); 03389 } else 03390 lpTbInfo->pszText[0] = '\0'; 03391 } 03392 return nIndex; 03393 } 03394 03395 03396 static inline LRESULT 03397 TOOLBAR_GetButtonSize (const TOOLBAR_INFO *infoPtr) 03398 { 03399 return MAKELONG((WORD)infoPtr->nButtonWidth, 03400 (WORD)infoPtr->nButtonHeight); 03401 } 03402 03403 03404 static LRESULT 03405 TOOLBAR_GetButtonText (const TOOLBAR_INFO *infoPtr, INT Id, LPWSTR lpStr, BOOL isW) 03406 { 03407 INT nIndex; 03408 LPWSTR lpText; 03409 LRESULT ret = 0; 03410 03411 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03412 if (nIndex == -1) 03413 return -1; 03414 03415 lpText = TOOLBAR_GetText(infoPtr,&infoPtr->buttons[nIndex]); 03416 03417 if (isW) 03418 { 03419 if (lpText) 03420 { 03421 ret = strlenW (lpText); 03422 if (lpStr) strcpyW (lpStr, lpText); 03423 } 03424 } 03425 else 03426 ret = WideCharToMultiByte( CP_ACP, 0, lpText, -1, 03427 (LPSTR)lpStr, lpStr ? 0x7fffffff : 0, NULL, NULL ) - 1; 03428 return ret; 03429 } 03430 03431 03432 static LRESULT 03433 TOOLBAR_GetDisabledImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 03434 { 03435 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 03436 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 03437 return (LRESULT)GETDISIMAGELIST(infoPtr, wParam); 03438 } 03439 03440 03441 static inline LRESULT 03442 TOOLBAR_GetExtendedStyle (const TOOLBAR_INFO *infoPtr) 03443 { 03444 TRACE("\n"); 03445 03446 return infoPtr->dwExStyle; 03447 } 03448 03449 03450 static LRESULT 03451 TOOLBAR_GetHotImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 03452 { 03453 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 03454 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 03455 return (LRESULT)GETHOTIMAGELIST(infoPtr, wParam); 03456 } 03457 03458 03459 static LRESULT 03460 TOOLBAR_GetHotItem (const TOOLBAR_INFO *infoPtr) 03461 { 03462 if (!((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf))) 03463 return -1; 03464 03465 if (infoPtr->nHotItem < 0) 03466 return -1; 03467 03468 return (LRESULT)infoPtr->nHotItem; 03469 } 03470 03471 03472 static LRESULT 03473 TOOLBAR_GetDefImageList (const TOOLBAR_INFO *infoPtr, WPARAM wParam) 03474 { 03475 TRACE("hwnd=%p, wParam=%ld\n", infoPtr->hwndSelf, wParam); 03476 /* UNDOCUMENTED: wParam is actually the ID of the image list to return */ 03477 return (LRESULT) GETDEFIMAGELIST(infoPtr, wParam); 03478 } 03479 03480 03481 static LRESULT 03482 TOOLBAR_GetInsertMark (const TOOLBAR_INFO *infoPtr, TBINSERTMARK *lptbim) 03483 { 03484 TRACE("hwnd = %p, lptbim = %p\n", infoPtr->hwndSelf, lptbim); 03485 03486 *lptbim = infoPtr->tbim; 03487 03488 return 0; 03489 } 03490 03491 03492 static inline LRESULT 03493 TOOLBAR_GetInsertMarkColor (const TOOLBAR_INFO *infoPtr) 03494 { 03495 TRACE("hwnd = %p\n", infoPtr->hwndSelf); 03496 03497 return (LRESULT)infoPtr->clrInsertMark; 03498 } 03499 03500 03501 static LRESULT 03502 TOOLBAR_GetItemRect (const TOOLBAR_INFO *infoPtr, INT nIndex, LPRECT lpRect) 03503 { 03504 TBUTTON_INFO *btnPtr; 03505 03506 btnPtr = &infoPtr->buttons[nIndex]; 03507 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 03508 return FALSE; 03509 03510 if (lpRect == NULL) 03511 return FALSE; 03512 if (btnPtr->fsState & TBSTATE_HIDDEN) 03513 return FALSE; 03514 03515 lpRect->left = btnPtr->rect.left; 03516 lpRect->right = btnPtr->rect.right; 03517 lpRect->bottom = btnPtr->rect.bottom; 03518 lpRect->top = btnPtr->rect.top; 03519 03520 return TRUE; 03521 } 03522 03523 03524 static LRESULT 03525 TOOLBAR_GetMaxSize (const TOOLBAR_INFO *infoPtr, LPSIZE lpSize) 03526 { 03527 if (lpSize == NULL) 03528 return FALSE; 03529 03530 lpSize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 03531 lpSize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 03532 03533 TRACE("maximum size %d x %d\n", 03534 infoPtr->rcBound.right - infoPtr->rcBound.left, 03535 infoPtr->rcBound.bottom - infoPtr->rcBound.top); 03536 03537 return TRUE; 03538 } 03539 03540 03541 /* << TOOLBAR_GetObject >> */ 03542 03543 03544 static inline LRESULT 03545 TOOLBAR_GetPadding (const TOOLBAR_INFO *infoPtr) 03546 { 03547 return MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); 03548 } 03549 03550 03551 static LRESULT 03552 TOOLBAR_GetRect (const TOOLBAR_INFO *infoPtr, INT Id, LPRECT lpRect) 03553 { 03554 TBUTTON_INFO *btnPtr; 03555 INT nIndex; 03556 03557 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03558 btnPtr = &infoPtr->buttons[nIndex]; 03559 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 03560 return FALSE; 03561 03562 if (lpRect == NULL) 03563 return FALSE; 03564 03565 lpRect->left = btnPtr->rect.left; 03566 lpRect->right = btnPtr->rect.right; 03567 lpRect->bottom = btnPtr->rect.bottom; 03568 lpRect->top = btnPtr->rect.top; 03569 03570 return TRUE; 03571 } 03572 03573 03574 static inline LRESULT 03575 TOOLBAR_GetRows (const TOOLBAR_INFO *infoPtr) 03576 { 03577 return infoPtr->nRows; 03578 } 03579 03580 03581 static LRESULT 03582 TOOLBAR_GetState (const TOOLBAR_INFO *infoPtr, INT Id) 03583 { 03584 INT nIndex; 03585 03586 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03587 if (nIndex == -1) 03588 return -1; 03589 03590 return infoPtr->buttons[nIndex].fsState; 03591 } 03592 03593 03594 static inline LRESULT 03595 TOOLBAR_GetStyle (const TOOLBAR_INFO *infoPtr) 03596 { 03597 return infoPtr->dwStyle; 03598 } 03599 03600 03601 static inline LRESULT 03602 TOOLBAR_GetTextRows (const TOOLBAR_INFO *infoPtr) 03603 { 03604 return infoPtr->nMaxTextRows; 03605 } 03606 03607 03608 static LRESULT 03609 TOOLBAR_GetToolTips (TOOLBAR_INFO *infoPtr) 03610 { 03611 if ((infoPtr->dwStyle & TBSTYLE_TOOLTIPS) && (infoPtr->hwndToolTip == NULL)) 03612 TOOLBAR_TooltipCreateControl(infoPtr); 03613 return (LRESULT)infoPtr->hwndToolTip; 03614 } 03615 03616 03617 static LRESULT 03618 TOOLBAR_GetUnicodeFormat (const TOOLBAR_INFO *infoPtr) 03619 { 03620 TRACE("%s hwnd=%p\n", 03621 infoPtr->bUnicode ? "TRUE" : "FALSE", infoPtr->hwndSelf); 03622 03623 return infoPtr->bUnicode; 03624 } 03625 03626 03627 static inline LRESULT 03628 TOOLBAR_GetVersion (const TOOLBAR_INFO *infoPtr) 03629 { 03630 return infoPtr->iVersion; 03631 } 03632 03633 03634 static LRESULT 03635 TOOLBAR_HideButton (TOOLBAR_INFO *infoPtr, INT Id, BOOL fHide) 03636 { 03637 TBUTTON_INFO *btnPtr; 03638 BYTE oldState; 03639 INT nIndex; 03640 03641 TRACE("\n"); 03642 03643 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03644 if (nIndex == -1) 03645 return FALSE; 03646 03647 btnPtr = &infoPtr->buttons[nIndex]; 03648 oldState = btnPtr->fsState; 03649 03650 if (fHide) 03651 btnPtr->fsState |= TBSTATE_HIDDEN; 03652 else 03653 btnPtr->fsState &= ~TBSTATE_HIDDEN; 03654 03655 if (oldState != btnPtr->fsState) { 03656 TOOLBAR_LayoutToolbar (infoPtr); 03657 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 03658 } 03659 03660 return TRUE; 03661 } 03662 03663 03664 static inline LRESULT 03665 TOOLBAR_HitTest (const TOOLBAR_INFO *infoPtr, const POINT* lpPt) 03666 { 03667 return TOOLBAR_InternalHitTest (infoPtr, lpPt); 03668 } 03669 03670 03671 static LRESULT 03672 TOOLBAR_Indeterminate (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fIndeterminate) 03673 { 03674 TBUTTON_INFO *btnPtr; 03675 INT nIndex; 03676 DWORD oldState; 03677 03678 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03679 if (nIndex == -1) 03680 return FALSE; 03681 03682 btnPtr = &infoPtr->buttons[nIndex]; 03683 oldState = btnPtr->fsState; 03684 03685 if (fIndeterminate) 03686 btnPtr->fsState |= TBSTATE_INDETERMINATE; 03687 else 03688 btnPtr->fsState &= ~TBSTATE_INDETERMINATE; 03689 03690 if(oldState != btnPtr->fsState) 03691 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03692 03693 return TRUE; 03694 } 03695 03696 03697 static LRESULT 03698 TOOLBAR_InsertButtonT(TOOLBAR_INFO *infoPtr, INT nIndex, const TBBUTTON *lpTbb, BOOL fUnicode) 03699 { 03700 if (lpTbb == NULL) 03701 return FALSE; 03702 03703 if (nIndex == -1) { 03704 /* EPP: this seems to be an undocumented call (from my IE4) 03705 * I assume in that case that: 03706 * - index of insertion is at the end of existing buttons 03707 * I only see this happen with nIndex == -1, but it could have a special 03708 * meaning (like -nIndex (or ~nIndex) to get the real position of insertion). 03709 */ 03710 nIndex = infoPtr->nNumButtons; 03711 03712 } else if (nIndex < 0) 03713 return FALSE; 03714 03715 TRACE("inserting button index=%d\n", nIndex); 03716 if (nIndex > infoPtr->nNumButtons) { 03717 nIndex = infoPtr->nNumButtons; 03718 TRACE("adjust index=%d\n", nIndex); 03719 } 03720 03721 return TOOLBAR_InternalInsertButtonsT(infoPtr, nIndex, 1, lpTbb, fUnicode); 03722 } 03723 03724 /* << TOOLBAR_InsertMarkHitTest >> */ 03725 03726 03727 static LRESULT 03728 TOOLBAR_IsButtonChecked (const TOOLBAR_INFO *infoPtr, INT Id) 03729 { 03730 INT nIndex; 03731 03732 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03733 if (nIndex == -1) 03734 return -1; 03735 03736 return (infoPtr->buttons[nIndex].fsState & TBSTATE_CHECKED); 03737 } 03738 03739 03740 static LRESULT 03741 TOOLBAR_IsButtonEnabled (const TOOLBAR_INFO *infoPtr, INT Id) 03742 { 03743 INT nIndex; 03744 03745 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03746 if (nIndex == -1) 03747 return -1; 03748 03749 return (infoPtr->buttons[nIndex].fsState & TBSTATE_ENABLED); 03750 } 03751 03752 03753 static LRESULT 03754 TOOLBAR_IsButtonHidden (const TOOLBAR_INFO *infoPtr, INT Id) 03755 { 03756 INT nIndex; 03757 03758 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03759 if (nIndex == -1) 03760 return -1; 03761 03762 return (infoPtr->buttons[nIndex].fsState & TBSTATE_HIDDEN); 03763 } 03764 03765 03766 static LRESULT 03767 TOOLBAR_IsButtonHighlighted (const TOOLBAR_INFO *infoPtr, INT Id) 03768 { 03769 INT nIndex; 03770 03771 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03772 if (nIndex == -1) 03773 return -1; 03774 03775 return (infoPtr->buttons[nIndex].fsState & TBSTATE_MARKED); 03776 } 03777 03778 03779 static LRESULT 03780 TOOLBAR_IsButtonIndeterminate (const TOOLBAR_INFO *infoPtr, INT Id) 03781 { 03782 INT nIndex; 03783 03784 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03785 if (nIndex == -1) 03786 return -1; 03787 03788 return (infoPtr->buttons[nIndex].fsState & TBSTATE_INDETERMINATE); 03789 } 03790 03791 03792 static LRESULT 03793 TOOLBAR_IsButtonPressed (const TOOLBAR_INFO *infoPtr, INT Id) 03794 { 03795 INT nIndex; 03796 03797 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03798 if (nIndex == -1) 03799 return -1; 03800 03801 return (infoPtr->buttons[nIndex].fsState & TBSTATE_PRESSED); 03802 } 03803 03804 03805 static LRESULT 03806 TOOLBAR_LoadImages (TOOLBAR_INFO *infoPtr, WPARAM wParam, HINSTANCE hInstance) 03807 { 03808 TBADDBITMAP tbab; 03809 tbab.hInst = hInstance; 03810 tbab.nID = wParam; 03811 03812 TRACE("hwnd = %p, hInst = %p, nID = %lu\n", infoPtr->hwndSelf, tbab.hInst, tbab.nID); 03813 03814 return TOOLBAR_AddBitmap(infoPtr, 0, &tbab); 03815 } 03816 03817 03818 static LRESULT 03819 TOOLBAR_MapAccelerator (const TOOLBAR_INFO *infoPtr, WCHAR wAccel, UINT *pIDButton) 03820 { 03821 WCHAR wszAccel[] = {'&',wAccel,0}; 03822 int i; 03823 03824 TRACE("hwnd = %p, wAccel = %x(%s), pIDButton = %p\n", 03825 infoPtr->hwndSelf, wAccel, debugstr_wn(&wAccel,1), pIDButton); 03826 03827 for (i = 0; i < infoPtr->nNumButtons; i++) 03828 { 03829 TBUTTON_INFO *btnPtr = infoPtr->buttons+i; 03830 if (!(btnPtr->fsStyle & BTNS_NOPREFIX) && 03831 !(btnPtr->fsState & TBSTATE_HIDDEN)) 03832 { 03833 int iLen = strlenW(wszAccel); 03834 LPCWSTR lpszStr = TOOLBAR_GetText(infoPtr, btnPtr); 03835 03836 if (!lpszStr) 03837 continue; 03838 03839 while (*lpszStr) 03840 { 03841 if ((lpszStr[0] == '&') && (lpszStr[1] == '&')) 03842 { 03843 lpszStr += 2; 03844 continue; 03845 } 03846 if (!strncmpiW(lpszStr, wszAccel, iLen)) 03847 { 03848 *pIDButton = btnPtr->idCommand; 03849 return TRUE; 03850 } 03851 lpszStr++; 03852 } 03853 } 03854 } 03855 return FALSE; 03856 } 03857 03858 03859 static LRESULT 03860 TOOLBAR_MarkButton (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fMark) 03861 { 03862 INT nIndex; 03863 DWORD oldState; 03864 TBUTTON_INFO *btnPtr; 03865 03866 TRACE("hwnd = %p, Id = %d, fMark = 0%d\n", infoPtr->hwndSelf, Id, fMark); 03867 03868 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03869 if (nIndex == -1) 03870 return FALSE; 03871 03872 btnPtr = &infoPtr->buttons[nIndex]; 03873 oldState = btnPtr->fsState; 03874 03875 if (fMark) 03876 btnPtr->fsState |= TBSTATE_MARKED; 03877 else 03878 btnPtr->fsState &= ~TBSTATE_MARKED; 03879 03880 if(oldState != btnPtr->fsState) 03881 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03882 03883 return TRUE; 03884 } 03885 03886 03887 /* fixes up an index of a button affected by a move */ 03888 static inline void TOOLBAR_MoveFixupIndex(INT* pIndex, INT nIndex, INT nMoveIndex, BOOL bMoveUp) 03889 { 03890 if (bMoveUp) 03891 { 03892 if (*pIndex > nIndex && *pIndex <= nMoveIndex) 03893 (*pIndex)--; 03894 else if (*pIndex == nIndex) 03895 *pIndex = nMoveIndex; 03896 } 03897 else 03898 { 03899 if (*pIndex >= nMoveIndex && *pIndex < nIndex) 03900 (*pIndex)++; 03901 else if (*pIndex == nIndex) 03902 *pIndex = nMoveIndex; 03903 } 03904 } 03905 03906 03907 static LRESULT 03908 TOOLBAR_MoveButton (TOOLBAR_INFO *infoPtr, INT Id, INT nMoveIndex) 03909 { 03910 INT nIndex; 03911 INT nCount; 03912 TBUTTON_INFO button; 03913 03914 TRACE("hwnd=%p, Id=%d, nMoveIndex=%d\n", infoPtr->hwndSelf, Id, nMoveIndex); 03915 03916 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, TRUE); 03917 if ((nIndex == -1) || (nMoveIndex < 0)) 03918 return FALSE; 03919 03920 if (nMoveIndex > infoPtr->nNumButtons - 1) 03921 nMoveIndex = infoPtr->nNumButtons - 1; 03922 03923 button = infoPtr->buttons[nIndex]; 03924 03925 /* move button right */ 03926 if (nIndex < nMoveIndex) 03927 { 03928 nCount = nMoveIndex - nIndex; 03929 memmove(&infoPtr->buttons[nIndex], &infoPtr->buttons[nIndex+1], nCount*sizeof(TBUTTON_INFO)); 03930 infoPtr->buttons[nMoveIndex] = button; 03931 03932 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, TRUE); 03933 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, TRUE); 03934 TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, TRUE); 03935 TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, TRUE); 03936 } 03937 else if (nIndex > nMoveIndex) /* move button left */ 03938 { 03939 nCount = nIndex - nMoveIndex; 03940 memmove(&infoPtr->buttons[nMoveIndex+1], &infoPtr->buttons[nMoveIndex], nCount*sizeof(TBUTTON_INFO)); 03941 infoPtr->buttons[nMoveIndex] = button; 03942 03943 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDown, nIndex, nMoveIndex, FALSE); 03944 TOOLBAR_MoveFixupIndex(&infoPtr->nButtonDrag, nIndex, nMoveIndex, FALSE); 03945 TOOLBAR_MoveFixupIndex(&infoPtr->nOldHit, nIndex, nMoveIndex, FALSE); 03946 TOOLBAR_MoveFixupIndex(&infoPtr->nHotItem, nIndex, nMoveIndex, FALSE); 03947 } 03948 03949 TOOLBAR_LayoutToolbar(infoPtr); 03950 TOOLBAR_AutoSize(infoPtr); 03951 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 03952 03953 return TRUE; 03954 } 03955 03956 03957 static LRESULT 03958 TOOLBAR_PressButton (const TOOLBAR_INFO *infoPtr, INT Id, BOOL fPress) 03959 { 03960 TBUTTON_INFO *btnPtr; 03961 INT nIndex; 03962 DWORD oldState; 03963 03964 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 03965 if (nIndex == -1) 03966 return FALSE; 03967 03968 btnPtr = &infoPtr->buttons[nIndex]; 03969 oldState = btnPtr->fsState; 03970 03971 if (fPress) 03972 btnPtr->fsState |= TBSTATE_PRESSED; 03973 else 03974 btnPtr->fsState &= ~TBSTATE_PRESSED; 03975 03976 if(oldState != btnPtr->fsState) 03977 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 03978 03979 return TRUE; 03980 } 03981 03982 /* FIXME: there might still be some confusion her between number of buttons 03983 * and number of bitmaps */ 03984 static LRESULT 03985 TOOLBAR_ReplaceBitmap (TOOLBAR_INFO *infoPtr, const TBREPLACEBITMAP *lpReplace) 03986 { 03987 HBITMAP hBitmap; 03988 int i = 0, nOldButtons = 0, pos = 0; 03989 int nOldBitmaps, nNewBitmaps = 0; 03990 HIMAGELIST himlDef = 0; 03991 03992 TRACE("hInstOld %p nIDOld %lx hInstNew %p nIDNew %lx nButtons %x\n", 03993 lpReplace->hInstOld, lpReplace->nIDOld, lpReplace->hInstNew, lpReplace->nIDNew, 03994 lpReplace->nButtons); 03995 03996 if (lpReplace->hInstOld == HINST_COMMCTRL) 03997 { 03998 FIXME("changing standard bitmaps not implemented\n"); 03999 return FALSE; 04000 } 04001 else if (lpReplace->hInstOld != 0 && lpReplace->hInstOld != lpReplace->hInstNew) 04002 FIXME("resources not in the current module not implemented\n"); 04003 04004 TRACE("To be replaced hInstOld %p nIDOld %lx\n", lpReplace->hInstOld, lpReplace->nIDOld); 04005 for (i = 0; i < infoPtr->nNumBitmapInfos; i++) { 04006 TBITMAP_INFO *tbi = &infoPtr->bitmaps[i]; 04007 TRACE("tbimapinfo %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); 04008 if (tbi->hInst == lpReplace->hInstOld && tbi->nID == lpReplace->nIDOld) 04009 { 04010 TRACE("Found: nButtons %d hInst %p nID %x\n", tbi->nButtons, tbi->hInst, tbi->nID); 04011 nOldButtons = tbi->nButtons; 04012 tbi->nButtons = lpReplace->nButtons; 04013 tbi->hInst = lpReplace->hInstNew; 04014 tbi->nID = lpReplace->nIDNew; 04015 TRACE("tbimapinfo changed %d hInstOld %p nIDOld %x\n", i, tbi->hInst, tbi->nID); 04016 break; 04017 } 04018 pos += tbi->nButtons; 04019 } 04020 04021 if (nOldButtons == 0) 04022 { 04023 WARN("No hinst/bitmap found! hInst %p nID %lx\n", lpReplace->hInstOld, lpReplace->nIDOld); 04024 return FALSE; 04025 } 04026 04027 /* copy the bitmap before adding it as ImageList_AddMasked modifies the 04028 * bitmap 04029 */ 04030 if (lpReplace->hInstNew) 04031 hBitmap = LoadBitmapW(lpReplace->hInstNew,(LPWSTR)lpReplace->nIDNew); 04032 else 04033 hBitmap = CopyImage((HBITMAP)lpReplace->nIDNew, IMAGE_BITMAP, 0, 0, 0); 04034 04035 himlDef = GETDEFIMAGELIST(infoPtr, 0); /* fixme: correct? */ 04036 nOldBitmaps = ImageList_GetImageCount(himlDef); 04037 04038 /* ImageList_Replace(GETDEFIMAGELIST(), pos, hBitmap, NULL); */ 04039 04040 for (i = pos + nOldBitmaps - 1; i >= pos; i--) 04041 ImageList_Remove(himlDef, i); 04042 04043 if (hBitmap) 04044 { 04045 ImageList_AddMasked (himlDef, hBitmap, comctl32_color.clrBtnFace); 04046 nNewBitmaps = ImageList_GetImageCount(himlDef); 04047 DeleteObject(hBitmap); 04048 } 04049 04050 infoPtr->nNumBitmaps = infoPtr->nNumBitmaps - nOldBitmaps + nNewBitmaps; 04051 04052 TRACE(" pos %d %d old bitmaps replaced by %d new ones.\n", 04053 pos, nOldBitmaps, nNewBitmaps); 04054 04055 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04056 return TRUE; 04057 } 04058 04059 04060 /* helper for TOOLBAR_SaveRestoreW */ 04061 static BOOL 04062 TOOLBAR_Save(const TBSAVEPARAMSW *lpSave) 04063 { 04064 FIXME("save to %s %s\n", debugstr_w(lpSave->pszSubKey), 04065 debugstr_w(lpSave->pszValueName)); 04066 04067 return FALSE; 04068 } 04069 04070 04071 /* helper for TOOLBAR_Restore */ 04072 static void 04073 TOOLBAR_DeleteAllButtons(TOOLBAR_INFO *infoPtr) 04074 { 04075 INT i; 04076 04077 for (i = 0; i < infoPtr->nNumButtons; i++) 04078 { 04079 TOOLBAR_TooltipDelTool(infoPtr, &infoPtr->buttons[i]); 04080 } 04081 04082 Free(infoPtr->buttons); 04083 infoPtr->buttons = NULL; 04084 infoPtr->nNumButtons = 0; 04085 } 04086 04087 04088 /* helper for TOOLBAR_SaveRestoreW */ 04089 static BOOL 04090 TOOLBAR_Restore(TOOLBAR_INFO *infoPtr, const TBSAVEPARAMSW *lpSave) 04091 { 04092 LONG res; 04093 HKEY hkey = NULL; 04094 BOOL ret = FALSE; 04095 DWORD dwType; 04096 DWORD dwSize = 0; 04097 NMTBRESTORE nmtbr; 04098 04099 /* restore toolbar information */ 04100 TRACE("restore from %s %s\n", debugstr_w(lpSave->pszSubKey), 04101 debugstr_w(lpSave->pszValueName)); 04102 04103 memset(&nmtbr, 0, sizeof(nmtbr)); 04104 04105 res = RegOpenKeyExW(lpSave->hkr, lpSave->pszSubKey, 0, 04106 KEY_QUERY_VALUE, &hkey); 04107 if (!res) 04108 res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, 04109 NULL, &dwSize); 04110 if (!res && dwType != REG_BINARY) 04111 res = ERROR_FILE_NOT_FOUND; 04112 if (!res) 04113 { 04114 nmtbr.pData = Alloc(dwSize); 04115 nmtbr.cbData = dwSize; 04116 if (!nmtbr.pData) res = ERROR_OUTOFMEMORY; 04117 } 04118 if (!res) 04119 res = RegQueryValueExW(hkey, lpSave->pszValueName, NULL, &dwType, 04120 (LPBYTE)nmtbr.pData, &dwSize); 04121 if (!res) 04122 { 04123 nmtbr.pCurrent = nmtbr.pData; 04124 nmtbr.iItem = -1; 04125 nmtbr.cbBytesPerRecord = sizeof(DWORD); 04126 nmtbr.cButtons = nmtbr.cbData / nmtbr.cbBytesPerRecord; 04127 04128 if (!TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE)) 04129 { 04130 INT i; 04131 04132 /* remove all existing buttons as this function is designed to 04133 * restore the toolbar to a previously saved state */ 04134 TOOLBAR_DeleteAllButtons(infoPtr); 04135 04136 for (i = 0; i < nmtbr.cButtons; i++) 04137 { 04138 nmtbr.iItem = i; 04139 nmtbr.tbButton.iBitmap = -1; 04140 nmtbr.tbButton.fsState = 0; 04141 nmtbr.tbButton.fsStyle = 0; 04142 nmtbr.tbButton.idCommand = 0; 04143 if (*nmtbr.pCurrent == (DWORD)-1) 04144 { 04145 /* separator */ 04146 nmtbr.tbButton.fsStyle = TBSTYLE_SEP; 04147 /* when inserting separators, iBitmap controls it's size. 04148 0 sets default size (width) */ 04149 nmtbr.tbButton.iBitmap = 0; 04150 } 04151 else if (*nmtbr.pCurrent == (DWORD)-2) 04152 /* hidden button */ 04153 nmtbr.tbButton.fsState = TBSTATE_HIDDEN; 04154 else 04155 nmtbr.tbButton.idCommand = (int)*nmtbr.pCurrent; 04156 04157 nmtbr.pCurrent++; 04158 04159 TOOLBAR_SendNotify(&nmtbr.hdr, infoPtr, TBN_RESTORE); 04160 04161 /* can't contain real string as we don't know whether 04162 * the client put an ANSI or Unicode string in there */ 04163 if (!IS_INTRESOURCE(nmtbr.tbButton.iString)) 04164 nmtbr.tbButton.iString = 0; 04165 04166 TOOLBAR_InsertButtonT(infoPtr, -1, &nmtbr.tbButton, TRUE); 04167 } 04168 04169 /* do legacy notifications */ 04170 if (infoPtr->iVersion < 5) 04171 { 04172 /* FIXME: send TBN_BEGINADJUST */ 04173 FIXME("send TBN_GETBUTTONINFO for each button\n"); 04174 /* FIXME: send TBN_ENDADJUST */ 04175 } 04176 04177 /* remove all uninitialised buttons 04178 * note: loop backwards to avoid having to fixup i on a 04179 * delete */ 04180 for (i = infoPtr->nNumButtons - 1; i >= 0; i--) 04181 if (infoPtr->buttons[i].iBitmap == -1) 04182 TOOLBAR_DeleteButton(infoPtr, i); 04183 04184 /* only indicate success if at least one button survived */ 04185 if (infoPtr->nNumButtons > 0) ret = TRUE; 04186 } 04187 } 04188 Free (nmtbr.pData); 04189 RegCloseKey(hkey); 04190 04191 return ret; 04192 } 04193 04194 04195 static LRESULT 04196 TOOLBAR_SaveRestoreW (TOOLBAR_INFO *infoPtr, WPARAM wParam, const TBSAVEPARAMSW *lpSave) 04197 { 04198 if (lpSave == NULL) return 0; 04199 04200 if (wParam) 04201 return TOOLBAR_Save(lpSave); 04202 else 04203 return TOOLBAR_Restore(infoPtr, lpSave); 04204 } 04205 04206 04207 static LRESULT 04208 TOOLBAR_SaveRestoreA (TOOLBAR_INFO *infoPtr, WPARAM wParam, const TBSAVEPARAMSA *lpSave) 04209 { 04210 LPWSTR pszValueName = 0, pszSubKey = 0; 04211 TBSAVEPARAMSW SaveW; 04212 LRESULT result = 0; 04213 int len; 04214 04215 if (lpSave == NULL) return 0; 04216 04217 len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, NULL, 0); 04218 pszSubKey = Alloc(len * sizeof(WCHAR)); 04219 if (pszSubKey) goto exit; 04220 MultiByteToWideChar(CP_ACP, 0, lpSave->pszSubKey, -1, pszSubKey, len); 04221 04222 len = MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, NULL, 0); 04223 pszValueName = Alloc(len * sizeof(WCHAR)); 04224 if (!pszValueName) goto exit; 04225 MultiByteToWideChar(CP_ACP, 0, lpSave->pszValueName, -1, pszValueName, len); 04226 04227 SaveW.pszValueName = pszValueName; 04228 SaveW.pszSubKey = pszSubKey; 04229 SaveW.hkr = lpSave->hkr; 04230 result = TOOLBAR_SaveRestoreW(infoPtr, wParam, &SaveW); 04231 04232 exit: 04233 Free (pszValueName); 04234 Free (pszSubKey); 04235 04236 return result; 04237 } 04238 04239 04240 static LRESULT 04241 TOOLBAR_SetAnchorHighlight (TOOLBAR_INFO *infoPtr, BOOL bAnchor) 04242 { 04243 BOOL bOldAnchor = infoPtr->bAnchor; 04244 04245 TRACE("hwnd=%p, bAnchor = %s\n", infoPtr->hwndSelf, bAnchor ? "TRUE" : "FALSE"); 04246 04247 infoPtr->bAnchor = bAnchor; 04248 04249 /* Native does not remove the hot effect from an already hot button */ 04250 04251 return (LRESULT)bOldAnchor; 04252 } 04253 04254 04255 static LRESULT 04256 TOOLBAR_SetBitmapSize (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 04257 { 04258 HIMAGELIST himlDef = GETDEFIMAGELIST(infoPtr, 0); 04259 short width = (short)LOWORD(lParam); 04260 short height = (short)HIWORD(lParam); 04261 04262 TRACE("hwnd=%p, wParam=%ld, lParam=%ld\n", infoPtr->hwndSelf, wParam, lParam); 04263 04264 if (wParam != 0) 04265 FIXME("wParam is %ld. Perhaps image list index?\n", wParam); 04266 04267 /* 0 width or height is changed to 1 */ 04268 if (width == 0) 04269 width = 1; 04270 if (height == 0) 04271 height = 1; 04272 04273 if (infoPtr->nNumButtons > 0) 04274 TRACE("%d buttons, undoc change to bitmap size : %d-%d -> %d-%d\n", 04275 infoPtr->nNumButtons, 04276 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, width, height); 04277 04278 if (width < -1 || height < -1) 04279 { 04280 /* Windows destroys the imagelist and seems to actually use negative 04281 * values to compute button sizes */ 04282 FIXME("Negative bitmap sizes not supported (%d, %d)\n", width, height); 04283 return FALSE; 04284 } 04285 04286 /* width or height of -1 means no change */ 04287 if (width != -1) 04288 infoPtr->nBitmapWidth = width; 04289 if (height != -1) 04290 infoPtr->nBitmapHeight = height; 04291 04292 if ((himlDef == infoPtr->himlInt) && 04293 (ImageList_GetImageCount(infoPtr->himlInt) == 0)) 04294 { 04295 ImageList_SetIconSize(infoPtr->himlInt, infoPtr->nBitmapWidth, 04296 infoPtr->nBitmapHeight); 04297 } 04298 04299 TOOLBAR_CalcToolbar(infoPtr); 04300 InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); 04301 return TRUE; 04302 } 04303 04304 04305 static LRESULT 04306 TOOLBAR_SetButtonInfo (TOOLBAR_INFO *infoPtr, INT Id, 04307 const TBBUTTONINFOW *lptbbi, BOOL isW) 04308 { 04309 TBUTTON_INFO *btnPtr; 04310 INT nIndex; 04311 RECT oldBtnRect; 04312 04313 if (lptbbi == NULL) 04314 return FALSE; 04315 if (lptbbi->cbSize < sizeof(TBBUTTONINFOW)) 04316 return FALSE; 04317 04318 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, lptbbi->dwMask & TBIF_BYINDEX); 04319 if (nIndex == -1) 04320 return FALSE; 04321 04322 btnPtr = &infoPtr->buttons[nIndex]; 04323 if (lptbbi->dwMask & TBIF_COMMAND) 04324 btnPtr->idCommand = lptbbi->idCommand; 04325 if (lptbbi->dwMask & TBIF_IMAGE) 04326 btnPtr->iBitmap = lptbbi->iImage; 04327 if (lptbbi->dwMask & TBIF_LPARAM) 04328 btnPtr->dwData = lptbbi->lParam; 04329 if (lptbbi->dwMask & TBIF_SIZE) 04330 btnPtr->cx = lptbbi->cx; 04331 if (lptbbi->dwMask & TBIF_STATE) 04332 btnPtr->fsState = lptbbi->fsState; 04333 if (lptbbi->dwMask & TBIF_STYLE) 04334 btnPtr->fsStyle = lptbbi->fsStyle; 04335 04336 if ((lptbbi->dwMask & TBIF_TEXT) && ((INT_PTR)lptbbi->pszText != -1)) { 04337 /* iString is index, zero it to make Str_SetPtr succeed */ 04338 if (!TOOLBAR_ButtonHasString(btnPtr)) btnPtr->iString = 0; 04339 04340 if (isW) 04341 Str_SetPtrW ((LPWSTR *)&btnPtr->iString, lptbbi->pszText); 04342 else 04343 Str_SetPtrAtoW ((LPWSTR *)&btnPtr->iString, (LPSTR)lptbbi->pszText); 04344 } 04345 04346 /* save the button rect to see if we need to redraw the whole toolbar */ 04347 oldBtnRect = btnPtr->rect; 04348 TOOLBAR_LayoutToolbar(infoPtr); 04349 04350 if (!EqualRect(&oldBtnRect, &btnPtr->rect)) 04351 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04352 else 04353 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 04354 04355 return TRUE; 04356 } 04357 04358 04359 static LRESULT 04360 TOOLBAR_SetButtonSize (TOOLBAR_INFO *infoPtr, LPARAM lParam) 04361 { 04362 INT cx = (short)LOWORD(lParam), cy = (short)HIWORD(lParam); 04363 04364 if ((cx < 0) || (cy < 0)) 04365 { 04366 ERR("invalid parameter 0x%08x\n", (DWORD)lParam); 04367 return FALSE; 04368 } 04369 04370 TRACE("%p, cx = %d, cy = %d\n", infoPtr->hwndSelf, cx, cy); 04371 04372 /* The documentation claims you can only change the button size before 04373 * any button has been added. But this is wrong. 04374 * WINZIP32.EXE (ver 8) calls this on one of its buttons after adding 04375 * it to the toolbar, and it checks that the return value is nonzero - mjm 04376 * Further testing shows that we must actually perform the change too. 04377 */ 04378 /* 04379 * The documentation also does not mention that if 0 is supplied for 04380 * either size, the system changes it to the default of 24 wide and 04381 * 22 high. Demonstrated in ControlSpy Toolbar. GLA 3/02 04382 */ 04383 if (cx == 0) cx = 24; 04384 if (cy == 0) cy = 22; 04385 04386 cx = max(cx, infoPtr->szPadding.cx + infoPtr->nBitmapWidth); 04387 cy = max(cy, infoPtr->szPadding.cy + infoPtr->nBitmapHeight); 04388 04389 infoPtr->nButtonWidth = cx; 04390 infoPtr->nButtonHeight = cy; 04391 04392 infoPtr->iTopMargin = default_top_margin(infoPtr); 04393 TOOLBAR_LayoutToolbar(infoPtr); 04394 return TRUE; 04395 } 04396 04397 04398 static LRESULT 04399 TOOLBAR_SetButtonWidth (TOOLBAR_INFO *infoPtr, LPARAM lParam) 04400 { 04401 /* if setting to current values, ignore */ 04402 if ((infoPtr->cxMin == (short)LOWORD(lParam)) && 04403 (infoPtr->cxMax == (short)HIWORD(lParam))) { 04404 TRACE("matches current width, min=%d, max=%d, no recalc\n", 04405 infoPtr->cxMin, infoPtr->cxMax); 04406 return TRUE; 04407 } 04408 04409 /* save new values */ 04410 infoPtr->cxMin = (short)LOWORD(lParam); 04411 infoPtr->cxMax = (short)HIWORD(lParam); 04412 04413 /* otherwise we need to recalc the toolbar and in some cases 04414 recalc the bounding rectangle (does DrawText w/ DT_CALCRECT 04415 which doesn't actually draw - GA). */ 04416 TRACE("number of buttons %d, cx=%d, cy=%d, recalcing\n", 04417 infoPtr->nNumButtons, infoPtr->cxMin, infoPtr->cxMax); 04418 04419 TOOLBAR_CalcToolbar (infoPtr); 04420 04421 InvalidateRect (infoPtr->hwndSelf, NULL, TRUE); 04422 04423 return TRUE; 04424 } 04425 04426 04427 static LRESULT 04428 TOOLBAR_SetCmdId (TOOLBAR_INFO *infoPtr, INT nIndex, INT nId) 04429 { 04430 if ((nIndex < 0) || (nIndex >= infoPtr->nNumButtons)) 04431 return FALSE; 04432 04433 infoPtr->buttons[nIndex].idCommand = nId; 04434 04435 if (infoPtr->hwndToolTip) { 04436 04437 FIXME("change tool tip!\n"); 04438 04439 } 04440 04441 return TRUE; 04442 } 04443 04444 04445 static LRESULT 04446 TOOLBAR_SetDisabledImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 04447 { 04448 HIMAGELIST himlTemp; 04449 INT id = 0; 04450 04451 if (infoPtr->iVersion >= 5) 04452 id = wParam; 04453 04454 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDis, 04455 &infoPtr->cimlDis, himl, id); 04456 04457 /* FIXME: redraw ? */ 04458 04459 return (LRESULT)himlTemp; 04460 } 04461 04462 04463 static LRESULT 04464 TOOLBAR_SetDrawTextFlags (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 04465 { 04466 DWORD dwTemp; 04467 04468 TRACE("hwnd = %p, dwMask = 0x%08x, dwDTFlags = 0x%08x\n", infoPtr->hwndSelf, (DWORD)wParam, (DWORD)lParam); 04469 04470 dwTemp = infoPtr->dwDTFlags; 04471 infoPtr->dwDTFlags = 04472 (infoPtr->dwDTFlags & (DWORD)wParam) | (DWORD)lParam; 04473 04474 return (LRESULT)dwTemp; 04475 } 04476 04477 /* This function differs a bit from what MSDN says it does: 04478 * 1. lParam contains extended style flags to OR with current style 04479 * (MSDN isn't clear on the OR bit) 04480 * 2. wParam appears to contain extended style flags to be reset 04481 * (MSDN says that this parameter is reserved) 04482 */ 04483 static LRESULT 04484 TOOLBAR_SetExtendedStyle (TOOLBAR_INFO *infoPtr, LPARAM lParam) 04485 { 04486 DWORD dwOldStyle; 04487 04488 dwOldStyle = infoPtr->dwExStyle; 04489 infoPtr->dwExStyle = (DWORD)lParam; 04490 04491 TRACE("new style 0x%08x\n", infoPtr->dwExStyle); 04492 04493 if (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL) 04494 FIXME("Unknown Toolbar Extended Style 0x%08x. Please report.\n", 04495 (infoPtr->dwExStyle & ~TBSTYLE_EX_ALL)); 04496 04497 if ((dwOldStyle ^ infoPtr->dwExStyle) & TBSTYLE_EX_MIXEDBUTTONS) 04498 TOOLBAR_CalcToolbar(infoPtr); 04499 else 04500 TOOLBAR_LayoutToolbar(infoPtr); 04501 04502 TOOLBAR_AutoSize(infoPtr); 04503 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04504 04505 return (LRESULT)dwOldStyle; 04506 } 04507 04508 04509 static LRESULT 04510 TOOLBAR_SetHotImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 04511 { 04512 HIMAGELIST himlTemp; 04513 INT id = 0; 04514 04515 if (infoPtr->iVersion >= 5) 04516 id = wParam; 04517 04518 TRACE("hwnd = %p, himl = %p, id = %d\n", infoPtr->hwndSelf, himl, id); 04519 04520 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlHot, 04521 &infoPtr->cimlHot, himl, id); 04522 04523 /* FIXME: redraw ? */ 04524 04525 return (LRESULT)himlTemp; 04526 } 04527 04528 04529 /* Makes previous hot button no longer hot, makes the specified 04530 * button hot and sends appropriate notifications. dwReason is one or 04531 * more HICF_ flags. Specify nHit < 0 to make no buttons hot. 04532 * NOTE 1: this function does not validate nHit 04533 * NOTE 2: the name of this function is completely made up and 04534 * not based on any documentation from Microsoft. */ 04535 static void 04536 TOOLBAR_SetHotItemEx (TOOLBAR_INFO *infoPtr, INT nHit, DWORD dwReason) 04537 { 04538 if (infoPtr->nHotItem != nHit) 04539 { 04540 NMTBHOTITEM nmhotitem; 04541 TBUTTON_INFO *btnPtr = NULL, *oldBtnPtr = NULL; 04542 04543 nmhotitem.dwFlags = dwReason; 04544 if(infoPtr->nHotItem >= 0) 04545 { 04546 oldBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; 04547 nmhotitem.idOld = oldBtnPtr->idCommand; 04548 } 04549 else 04550 { 04551 nmhotitem.dwFlags |= HICF_ENTERING; 04552 nmhotitem.idOld = 0; 04553 } 04554 04555 if (nHit >= 0) 04556 { 04557 btnPtr = &infoPtr->buttons[nHit]; 04558 nmhotitem.idNew = btnPtr->idCommand; 04559 } 04560 else 04561 { 04562 nmhotitem.dwFlags |= HICF_LEAVING; 04563 nmhotitem.idNew = 0; 04564 } 04565 04566 /* now change the hot and invalidate the old and new buttons - if the 04567 * parent agrees */ 04568 if (!TOOLBAR_SendNotify(&nmhotitem.hdr, infoPtr, TBN_HOTITEMCHANGE)) 04569 { 04570 if (oldBtnPtr) { 04571 oldBtnPtr->bHot = FALSE; 04572 InvalidateRect(infoPtr->hwndSelf, &oldBtnPtr->rect, TRUE); 04573 } 04574 /* setting disabled buttons as hot fails even if the notify contains the button id */ 04575 if (btnPtr && (btnPtr->fsState & TBSTATE_ENABLED)) { 04576 btnPtr->bHot = TRUE; 04577 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 04578 infoPtr->nHotItem = nHit; 04579 } 04580 else 04581 infoPtr->nHotItem = -1; 04582 } 04583 } 04584 } 04585 04586 static LRESULT 04587 TOOLBAR_SetHotItem (TOOLBAR_INFO *infoPtr, INT nHotItem) 04588 { 04589 INT nOldHotItem = infoPtr->nHotItem; 04590 04591 TRACE("hwnd = %p, nHotItem = %d\n", infoPtr->hwndSelf, nHotItem); 04592 04593 if (nHotItem >= infoPtr->nNumButtons) 04594 return infoPtr->nHotItem; 04595 04596 if (nHotItem < 0) 04597 nHotItem = -1; 04598 04599 /* NOTE: an application can still remove the hot item even if anchor 04600 * highlighting is enabled */ 04601 04602 TOOLBAR_SetHotItemEx(infoPtr, nHotItem, HICF_OTHER); 04603 04604 if (nOldHotItem < 0) 04605 return -1; 04606 04607 return (LRESULT)nOldHotItem; 04608 } 04609 04610 04611 static LRESULT 04612 TOOLBAR_SetImageList (TOOLBAR_INFO *infoPtr, WPARAM wParam, HIMAGELIST himl) 04613 { 04614 HIMAGELIST himlTemp; 04615 INT oldButtonWidth = infoPtr->nButtonWidth; 04616 INT oldBitmapWidth = infoPtr->nBitmapWidth; 04617 INT oldBitmapHeight = infoPtr->nBitmapHeight; 04618 INT i, id = 0; 04619 04620 if (infoPtr->iVersion >= 5) 04621 id = wParam; 04622 04623 himlTemp = TOOLBAR_InsertImageList(&infoPtr->himlDef, 04624 &infoPtr->cimlDef, himl, id); 04625 04626 infoPtr->nNumBitmaps = 0; 04627 for (i = 0; i < infoPtr->cimlDef; i++) 04628 infoPtr->nNumBitmaps += ImageList_GetImageCount(infoPtr->himlDef[i]->himl); 04629 04630 if (!ImageList_GetIconSize(himl, &infoPtr->nBitmapWidth, 04631 &infoPtr->nBitmapHeight)) 04632 { 04633 infoPtr->nBitmapWidth = 1; 04634 infoPtr->nBitmapHeight = 1; 04635 } 04636 if ((oldBitmapWidth != infoPtr->nBitmapWidth) || (oldBitmapHeight != infoPtr->nBitmapHeight)) 04637 { 04638 TOOLBAR_CalcToolbar(infoPtr); 04639 if (infoPtr->nButtonWidth < oldButtonWidth) 04640 TOOLBAR_SetButtonSize(infoPtr, MAKELONG(oldButtonWidth, infoPtr->nButtonHeight)); 04641 } 04642 04643 TRACE("hwnd %p, new himl=%p, id = %d, count=%d, bitmap w=%d, h=%d\n", 04644 infoPtr->hwndSelf, infoPtr->himlDef, id, infoPtr->nNumBitmaps, 04645 infoPtr->nBitmapWidth, infoPtr->nBitmapHeight); 04646 04647 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04648 04649 return (LRESULT)himlTemp; 04650 } 04651 04652 04653 static LRESULT 04654 TOOLBAR_SetIndent (TOOLBAR_INFO *infoPtr, INT nIndent) 04655 { 04656 infoPtr->nIndent = nIndent; 04657 04658 TRACE("\n"); 04659 04660 /* process only on indent changing */ 04661 if(infoPtr->nIndent != nIndent) 04662 { 04663 infoPtr->nIndent = nIndent; 04664 TOOLBAR_CalcToolbar (infoPtr); 04665 InvalidateRect(infoPtr->hwndSelf, NULL, FALSE); 04666 } 04667 04668 return TRUE; 04669 } 04670 04671 04672 static LRESULT 04673 TOOLBAR_SetInsertMark (TOOLBAR_INFO *infoPtr, const TBINSERTMARK *lptbim) 04674 { 04675 TRACE("hwnd = %p, lptbim = { %d, 0x%08x}\n", infoPtr->hwndSelf, lptbim->iButton, lptbim->dwFlags); 04676 04677 if ((lptbim->dwFlags & ~TBIMHT_AFTER) != 0) 04678 { 04679 FIXME("Unrecognized flag(s): 0x%08x\n", (lptbim->dwFlags & ~TBIMHT_AFTER)); 04680 return 0; 04681 } 04682 04683 if ((lptbim->iButton == -1) || 04684 ((lptbim->iButton < infoPtr->nNumButtons) && 04685 (lptbim->iButton >= 0))) 04686 { 04687 infoPtr->tbim = *lptbim; 04688 /* FIXME: don't need to update entire toolbar */ 04689 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04690 } 04691 else 04692 ERR("Invalid button index %d\n", lptbim->iButton); 04693 04694 return 0; 04695 } 04696 04697 04698 static LRESULT 04699 TOOLBAR_SetInsertMarkColor (TOOLBAR_INFO *infoPtr, COLORREF clr) 04700 { 04701 infoPtr->clrInsertMark = clr; 04702 04703 /* FIXME: don't need to update entire toolbar */ 04704 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04705 04706 return 0; 04707 } 04708 04709 04710 static LRESULT 04711 TOOLBAR_SetMaxTextRows (TOOLBAR_INFO *infoPtr, INT nMaxRows) 04712 { 04713 infoPtr->nMaxTextRows = nMaxRows; 04714 04715 TOOLBAR_CalcToolbar(infoPtr); 04716 return TRUE; 04717 } 04718 04719 04720 /* MSDN gives slightly wrong info on padding. 04721 * 1. It is not only used on buttons with the BTNS_AUTOSIZE style 04722 * 2. It is not used to create a blank area between the edge of the button 04723 * and the text or image if TBSTYLE_LIST is set. It is used to control 04724 * the gap between the image and text. 04725 * 3. It is not applied to both sides. If TBSTYLE_LIST is set it is used 04726 * to control the bottom and right borders [with the border being 04727 * szPadding.cx - (GetSystemMetrics(SM_CXEDGE)+1)], otherwise the padding 04728 * is shared evenly on both sides of the button. 04729 * See blueprints in comments above TOOLBAR_MeasureButton for more info. 04730 */ 04731 static LRESULT 04732 TOOLBAR_SetPadding (TOOLBAR_INFO *infoPtr, LPARAM lParam) 04733 { 04734 DWORD oldPad; 04735 04736 oldPad = MAKELONG(infoPtr->szPadding.cx, infoPtr->szPadding.cy); 04737 infoPtr->szPadding.cx = min(LOWORD((DWORD)lParam), GetSystemMetrics(SM_CXEDGE)); 04738 infoPtr->szPadding.cy = min(HIWORD((DWORD)lParam), GetSystemMetrics(SM_CYEDGE)); 04739 TRACE("cx=%d, cy=%d\n", 04740 infoPtr->szPadding.cx, infoPtr->szPadding.cy); 04741 return (LRESULT) oldPad; 04742 } 04743 04744 04745 static LRESULT 04746 TOOLBAR_SetParent (TOOLBAR_INFO *infoPtr, HWND hParent) 04747 { 04748 HWND hwndOldNotify; 04749 04750 TRACE("\n"); 04751 04752 hwndOldNotify = infoPtr->hwndNotify; 04753 infoPtr->hwndNotify = hParent; 04754 04755 return (LRESULT)hwndOldNotify; 04756 } 04757 04758 04759 static LRESULT 04760 TOOLBAR_SetRows (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPRECT lprc) 04761 { 04762 int rows = LOWORD(wParam); 04763 BOOL bLarger = HIWORD(wParam); 04764 04765 TRACE("\n"); 04766 04767 TRACE("Setting rows to %d (%d)\n", rows, bLarger); 04768 04769 if(infoPtr->nRows != rows) 04770 { 04771 TBUTTON_INFO *btnPtr = infoPtr->buttons; 04772 int curColumn = 0; /* Current column */ 04773 int curRow = 0; /* Current row */ 04774 int hidden = 0; /* Number of hidden buttons */ 04775 int seps = 0; /* Number of separators */ 04776 int idealWrap = 0; /* Ideal wrap point */ 04777 int i; 04778 BOOL wrap; 04779 04780 /* 04781 Calculate new size and wrap points - Under windows, setrows will 04782 change the dimensions if needed to show the number of requested 04783 rows (if CCS_NORESIZE is set), or will take up the whole window 04784 (if no CCS_NORESIZE). 04785 04786 Basic algorithm - If N buttons, and y rows requested, each row 04787 contains N/y buttons. 04788 04789 FIXME: Handling of separators not obvious from testing results 04790 FIXME: Take width of window into account? 04791 */ 04792 04793 /* Loop through the buttons one by one counting key items */ 04794 for (i = 0; i < infoPtr->nNumButtons; i++ ) 04795 { 04796 btnPtr[i].fsState &= ~TBSTATE_WRAP; 04797 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 04798 hidden++; 04799 else if (btnPtr[i].fsStyle & BTNS_SEP) 04800 seps++; 04801 } 04802 04803 /* FIXME: Separators make this quite complex */ 04804 if (seps) FIXME("Separators unhandled\n"); 04805 04806 /* Round up so more per line, i.e., less rows */ 04807 idealWrap = (infoPtr->nNumButtons - hidden + (rows-1)) / (rows ? rows : 1); 04808 04809 /* Calculate ideal wrap point if we are allowed to grow, but cannot 04810 achieve the requested number of rows. */ 04811 if (bLarger && idealWrap > 1) 04812 { 04813 int resRows = (infoPtr->nNumButtons + (idealWrap-1)) / idealWrap; 04814 int moreRows = (infoPtr->nNumButtons + (idealWrap-2)) / (idealWrap-1); 04815 04816 if (resRows < rows && moreRows > rows) 04817 { 04818 idealWrap--; 04819 TRACE("Changing idealWrap due to bLarger (now %d)\n", idealWrap); 04820 } 04821 } 04822 04823 curColumn = curRow = 0; 04824 wrap = FALSE; 04825 TRACE("Trying to wrap at %d (%d,%d,%d)\n", idealWrap, 04826 infoPtr->nNumButtons, hidden, rows); 04827 04828 for (i = 0; i < infoPtr->nNumButtons; i++ ) 04829 { 04830 if (btnPtr[i].fsState & TBSTATE_HIDDEN) 04831 continue; 04832 04833 /* Step on, wrap if necessary or flag next to wrap */ 04834 if (!wrap) { 04835 curColumn++; 04836 } else { 04837 wrap = FALSE; 04838 curColumn = 1; 04839 curRow++; 04840 } 04841 04842 if (curColumn > (idealWrap-1)) { 04843 wrap = TRUE; 04844 btnPtr[i].fsState |= TBSTATE_WRAP; 04845 } 04846 } 04847 04848 TRACE("Result - %d rows\n", curRow + 1); 04849 04850 /* recalculate toolbar */ 04851 TOOLBAR_CalcToolbar (infoPtr); 04852 04853 /* Resize if necessary (Only if NORESIZE is set - odd, but basically 04854 if NORESIZE is NOT set, then the toolbar will always be resized to 04855 take up the whole window. With it set, sizing needs to be manual. */ 04856 if (infoPtr->dwStyle & CCS_NORESIZE) { 04857 SetWindowPos(infoPtr->hwndSelf, NULL, 0, 0, 04858 infoPtr->rcBound.right - infoPtr->rcBound.left, 04859 infoPtr->rcBound.bottom - infoPtr->rcBound.top, 04860 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 04861 } 04862 04863 /* repaint toolbar */ 04864 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04865 } 04866 04867 /* return bounding rectangle */ 04868 if (lprc) { 04869 lprc->left = infoPtr->rcBound.left; 04870 lprc->right = infoPtr->rcBound.right; 04871 lprc->top = infoPtr->rcBound.top; 04872 lprc->bottom = infoPtr->rcBound.bottom; 04873 } 04874 04875 return 0; 04876 } 04877 04878 04879 static LRESULT 04880 TOOLBAR_SetState (TOOLBAR_INFO *infoPtr, INT Id, LPARAM lParam) 04881 { 04882 TBUTTON_INFO *btnPtr; 04883 INT nIndex; 04884 04885 nIndex = TOOLBAR_GetButtonIndex (infoPtr, Id, FALSE); 04886 if (nIndex == -1) 04887 return FALSE; 04888 04889 btnPtr = &infoPtr->buttons[nIndex]; 04890 04891 /* if hidden state has changed the invalidate entire window and recalc */ 04892 if ((btnPtr->fsState & TBSTATE_HIDDEN) != (LOWORD(lParam) & TBSTATE_HIDDEN)) { 04893 btnPtr->fsState = LOWORD(lParam); 04894 TOOLBAR_CalcToolbar (infoPtr); 04895 InvalidateRect(infoPtr->hwndSelf, 0, TRUE); 04896 return TRUE; 04897 } 04898 04899 /* process state changing if current state doesn't match new state */ 04900 if(btnPtr->fsState != LOWORD(lParam)) 04901 { 04902 btnPtr->fsState = LOWORD(lParam); 04903 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 04904 } 04905 04906 return TRUE; 04907 } 04908 04909 04910 static LRESULT 04911 TOOLBAR_SetStyle (TOOLBAR_INFO *infoPtr, DWORD style) 04912 { 04913 infoPtr->dwStyle = style; 04914 return 0; 04915 } 04916 04917 04918 static inline LRESULT 04919 TOOLBAR_SetToolTips (TOOLBAR_INFO *infoPtr, HWND hwndTooltip) 04920 { 04921 TRACE("hwnd=%p, hwndTooltip=%p\n", infoPtr->hwndSelf, hwndTooltip); 04922 04923 infoPtr->hwndToolTip = hwndTooltip; 04924 return 0; 04925 } 04926 04927 04928 static LRESULT 04929 TOOLBAR_SetUnicodeFormat (TOOLBAR_INFO *infoPtr, WPARAM wParam) 04930 { 04931 BOOL bTemp; 04932 04933 TRACE("%s hwnd=%p\n", 04934 ((BOOL)wParam) ? "TRUE" : "FALSE", infoPtr->hwndSelf); 04935 04936 bTemp = infoPtr->bUnicode; 04937 infoPtr->bUnicode = (BOOL)wParam; 04938 04939 return bTemp; 04940 } 04941 04942 04943 static LRESULT 04944 TOOLBAR_GetColorScheme (const TOOLBAR_INFO *infoPtr, LPCOLORSCHEME lParam) 04945 { 04946 lParam->clrBtnHighlight = (infoPtr->clrBtnHighlight == CLR_DEFAULT) ? 04947 comctl32_color.clrBtnHighlight : 04948 infoPtr->clrBtnHighlight; 04949 lParam->clrBtnShadow = (infoPtr->clrBtnShadow == CLR_DEFAULT) ? 04950 comctl32_color.clrBtnShadow : infoPtr->clrBtnShadow; 04951 return 1; 04952 } 04953 04954 04955 static LRESULT 04956 TOOLBAR_SetColorScheme (TOOLBAR_INFO *infoPtr, const COLORSCHEME *lParam) 04957 { 04958 TRACE("new colors Hl=%x Shd=%x, old colors Hl=%x Shd=%x\n", 04959 lParam->clrBtnHighlight, lParam->clrBtnShadow, 04960 infoPtr->clrBtnHighlight, infoPtr->clrBtnShadow); 04961 04962 infoPtr->clrBtnHighlight = lParam->clrBtnHighlight; 04963 infoPtr->clrBtnShadow = lParam->clrBtnShadow; 04964 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 04965 return 0; 04966 } 04967 04968 04969 static LRESULT 04970 TOOLBAR_SetVersion (TOOLBAR_INFO *infoPtr, INT iVersion) 04971 { 04972 INT iOldVersion = infoPtr->iVersion; 04973 04974 infoPtr->iVersion = iVersion; 04975 04976 if (infoPtr->iVersion >= 5) 04977 TOOLBAR_SetUnicodeFormat(infoPtr, TRUE); 04978 04979 return iOldVersion; 04980 } 04981 04982 04983 static LRESULT 04984 TOOLBAR_GetStringA (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPSTR str) 04985 { 04986 WORD iString = HIWORD(wParam); 04987 WORD buffersize = LOWORD(wParam); 04988 LRESULT ret = -1; 04989 04990 TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", infoPtr->hwndSelf, iString, buffersize, str); 04991 04992 if (iString < infoPtr->nNumStrings) 04993 { 04994 ret = WideCharToMultiByte(CP_ACP, 0, infoPtr->strings[iString], -1, str, buffersize, NULL, NULL); 04995 ret--; 04996 04997 TRACE("returning %s\n", debugstr_a(str)); 04998 } 04999 else 05000 WARN("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); 05001 05002 return ret; 05003 } 05004 05005 05006 static LRESULT 05007 TOOLBAR_GetStringW (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPWSTR str) 05008 { 05009 WORD iString = HIWORD(wParam); 05010 WORD len = LOWORD(wParam)/sizeof(WCHAR) - 1; 05011 LRESULT ret = -1; 05012 05013 TRACE("hwnd=%p, iString=%d, buffersize=%d, string=%p\n", infoPtr->hwndSelf, iString, LOWORD(wParam), str); 05014 05015 if (iString < infoPtr->nNumStrings) 05016 { 05017 len = min(len, strlenW(infoPtr->strings[iString])); 05018 ret = (len+1)*sizeof(WCHAR); 05019 if (str) 05020 { 05021 memcpy(str, infoPtr->strings[iString], ret); 05022 str[len] = '\0'; 05023 } 05024 ret = len; 05025 05026 TRACE("returning %s\n", debugstr_w(str)); 05027 } 05028 else 05029 WARN("String index %d out of range (largest is %d)\n", iString, infoPtr->nNumStrings - 1); 05030 05031 return ret; 05032 } 05033 05034 /* UNDOCUMENTED MESSAGE: This appears to set some kind of size. Perhaps it 05035 * is the maximum size of the toolbar? */ 05036 static LRESULT TOOLBAR_Unkwn45D(HWND hwnd, WPARAM wParam, LPARAM lParam) 05037 { 05038 SIZE * pSize = (SIZE*)lParam; 05039 FIXME("hwnd=%p, wParam=0x%08lx, size.cx=%d, size.cy=%d stub!\n", hwnd, wParam, pSize->cx, pSize->cy); 05040 return 0; 05041 } 05042 05043 05044 /* This is an extended version of the TB_SETHOTITEM message. It allows the 05045 * caller to specify a reason why the hot item changed (rather than just the 05046 * HICF_OTHER that TB_SETHOTITEM sends). */ 05047 static LRESULT 05048 TOOLBAR_SetHotItem2 (TOOLBAR_INFO *infoPtr, INT nHotItem, LPARAM lParam) 05049 { 05050 INT nOldHotItem = infoPtr->nHotItem; 05051 05052 TRACE("old item=%d, new item=%d, flags=%08x\n", 05053 nOldHotItem, nHotItem, (DWORD)lParam); 05054 05055 if (nHotItem < 0 || nHotItem > infoPtr->nNumButtons) 05056 nHotItem = -1; 05057 05058 /* NOTE: an application can still remove the hot item even if anchor 05059 * highlighting is enabled */ 05060 05061 TOOLBAR_SetHotItemEx(infoPtr, nHotItem, lParam); 05062 05063 GetFocus(); 05064 05065 return (nOldHotItem < 0) ? -1 : (LRESULT)nOldHotItem; 05066 } 05067 05068 /* Sets the toolbar global iListGap parameter which controls the amount of 05069 * spacing between the image and the text of buttons for TBSTYLE_LIST 05070 * toolbars. */ 05071 static LRESULT TOOLBAR_SetListGap(TOOLBAR_INFO *infoPtr, INT iListGap) 05072 { 05073 TRACE("hwnd=%p iListGap=%d\n", infoPtr->hwndSelf, iListGap); 05074 05075 infoPtr->iListGap = iListGap; 05076 05077 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 05078 05079 return 0; 05080 } 05081 05082 /* Returns the number of maximum number of image lists associated with the 05083 * various states. */ 05084 static LRESULT TOOLBAR_GetImageListCount(const TOOLBAR_INFO *infoPtr) 05085 { 05086 TRACE("hwnd=%p\n", infoPtr->hwndSelf); 05087 05088 return max(infoPtr->cimlDef, max(infoPtr->cimlHot, infoPtr->cimlDis)); 05089 } 05090 05091 static LRESULT 05092 TOOLBAR_GetIdealSize (const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05093 { 05094 LPSIZE lpsize = (LPSIZE)lParam; 05095 05096 if (lpsize == NULL) 05097 return FALSE; 05098 05099 /* 05100 * Testing shows the following: 05101 * wParam = 0 adjust cx value 05102 * = 1 set cy value to max size. 05103 * lParam pointer to SIZE structure 05104 * 05105 */ 05106 TRACE("wParam %ld, lParam 0x%08lx -> 0x%08x 0x%08x\n", 05107 wParam, lParam, lpsize->cx, lpsize->cy); 05108 05109 switch(wParam) { 05110 case 0: 05111 if (lpsize->cx == -1) { 05112 /* **** this is wrong, native measures each button and sets it */ 05113 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 05114 } 05115 else if(HIWORD(lpsize->cx)) { 05116 RECT rc; 05117 HWND hwndParent = GetParent(infoPtr->hwndSelf); 05118 05119 GetWindowRect(infoPtr->hwndSelf, &rc); 05120 MapWindowPoints(0, hwndParent, (LPPOINT)&rc, 2); 05121 TRACE("mapped to (%s)\n", wine_dbgstr_rect(&rc)); 05122 lpsize->cx = max(rc.right-rc.left, 05123 infoPtr->rcBound.right - infoPtr->rcBound.left); 05124 } 05125 else { 05126 lpsize->cx = infoPtr->rcBound.right - infoPtr->rcBound.left; 05127 } 05128 break; 05129 case 1: 05130 lpsize->cy = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 05131 break; 05132 default: 05133 FIXME("Unknown wParam %ld\n", wParam); 05134 return 0; 05135 } 05136 TRACE("set to -> 0x%08x 0x%08x\n", 05137 lpsize->cx, lpsize->cy); 05138 return 1; 05139 } 05140 05141 static LRESULT TOOLBAR_Unkwn464(HWND hwnd, WPARAM wParam, LPARAM lParam) 05142 { 05143 FIXME("hwnd=%p wParam %08lx lParam %08lx\n", hwnd, wParam, lParam); 05144 05145 InvalidateRect(hwnd, NULL, TRUE); 05146 return 1; 05147 } 05148 05149 05150 static LRESULT 05151 TOOLBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs) 05152 { 05153 TOOLBAR_INFO *infoPtr = (TOOLBAR_INFO *)GetWindowLongPtrW(hwnd, 0); 05154 LOGFONTW logFont; 05155 05156 TRACE("hwnd = %p, style=0x%08x\n", hwnd, lpcs->style); 05157 05158 infoPtr->dwStyle = lpcs->style; 05159 GetClientRect(hwnd, &infoPtr->client_rect); 05160 infoPtr->bUnicode = infoPtr->hwndNotify && 05161 (NFR_UNICODE == SendMessageW(hwnd, WM_NOTIFYFORMAT, (WPARAM)hwnd, NF_REQUERY)); 05162 infoPtr->hwndToolTip = NULL; /* if needed the tooltip control will be created after a WM_MOUSEMOVE */ 05163 05164 SystemParametersInfoW (SPI_GETICONTITLELOGFONT, 0, &logFont, 0); 05165 infoPtr->hFont = infoPtr->hDefaultFont = CreateFontIndirectW (&logFont); 05166 05167 OpenThemeData (hwnd, themeClass); 05168 05169 TOOLBAR_CheckStyle (infoPtr); 05170 05171 return 0; 05172 } 05173 05174 05175 static LRESULT 05176 TOOLBAR_Destroy (TOOLBAR_INFO *infoPtr) 05177 { 05178 INT i; 05179 05180 /* delete tooltip control */ 05181 if (infoPtr->hwndToolTip) 05182 DestroyWindow (infoPtr->hwndToolTip); 05183 05184 /* delete temporary buffer for tooltip text */ 05185 Free (infoPtr->pszTooltipText); 05186 Free (infoPtr->bitmaps); /* bitmaps list */ 05187 05188 /* delete button data */ 05189 for (i = 0; i < infoPtr->nNumButtons; i++) 05190 if (TOOLBAR_ButtonHasString(&infoPtr->buttons[i])) 05191 Free ((LPWSTR)infoPtr->buttons[i].iString); 05192 Free (infoPtr->buttons); 05193 05194 /* delete strings */ 05195 if (infoPtr->strings) { 05196 for (i = 0; i < infoPtr->nNumStrings; i++) 05197 Free (infoPtr->strings[i]); 05198 05199 Free (infoPtr->strings); 05200 } 05201 05202 /* destroy internal image list */ 05203 if (infoPtr->himlInt) 05204 ImageList_Destroy (infoPtr->himlInt); 05205 05206 TOOLBAR_DeleteImageList(&infoPtr->himlDef, &infoPtr->cimlDef); 05207 TOOLBAR_DeleteImageList(&infoPtr->himlDis, &infoPtr->cimlDis); 05208 TOOLBAR_DeleteImageList(&infoPtr->himlHot, &infoPtr->cimlHot); 05209 05210 /* delete default font */ 05211 DeleteObject (infoPtr->hDefaultFont); 05212 05213 CloseThemeData (GetWindowTheme (infoPtr->hwndSelf)); 05214 05215 /* free toolbar info data */ 05216 SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0); 05217 Free (infoPtr); 05218 05219 return 0; 05220 } 05221 05222 05223 static LRESULT 05224 TOOLBAR_EraseBackground (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05225 { 05226 NMTBCUSTOMDRAW tbcd; 05227 INT ret = FALSE; 05228 DWORD ntfret; 05229 HTHEME theme = GetWindowTheme (infoPtr->hwndSelf); 05230 DWORD dwEraseCustDraw = 0; 05231 05232 /* the app has told us not to redraw the toolbar */ 05233 if (!infoPtr->bDoRedraw) 05234 return FALSE; 05235 05236 if (infoPtr->dwStyle & TBSTYLE_CUSTOMERASE) { 05237 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 05238 tbcd.nmcd.dwDrawStage = CDDS_PREERASE; 05239 tbcd.nmcd.hdc = (HDC)wParam; 05240 ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 05241 dwEraseCustDraw = ntfret & 0xffff; 05242 05243 /* FIXME: in general the return flags *can* be or'ed together */ 05244 switch (dwEraseCustDraw) 05245 { 05246 case CDRF_DODEFAULT: 05247 break; 05248 case CDRF_SKIPDEFAULT: 05249 return TRUE; 05250 default: 05251 FIXME("[%p] response %d not handled to NM_CUSTOMDRAW (CDDS_PREERASE)\n", 05252 infoPtr->hwndSelf, ntfret); 05253 } 05254 } 05255 05256 /* If the toolbar is "transparent" then pass the WM_ERASEBKGND up 05257 * to my parent for processing. 05258 */ 05259 if (theme || (infoPtr->dwStyle & TBSTYLE_TRANSPARENT)) { 05260 POINT pt, ptorig; 05261 HDC hdc = (HDC)wParam; 05262 HWND parent; 05263 05264 pt.x = 0; 05265 pt.y = 0; 05266 parent = GetParent(infoPtr->hwndSelf); 05267 MapWindowPoints(infoPtr->hwndSelf, parent, &pt, 1); 05268 OffsetWindowOrgEx (hdc, pt.x, pt.y, &ptorig); 05269 ret = SendMessageW (parent, WM_ERASEBKGND, wParam, lParam); 05270 SetWindowOrgEx (hdc, ptorig.x, ptorig.y, 0); 05271 } 05272 if (!ret) 05273 ret = DefWindowProcW (infoPtr->hwndSelf, WM_ERASEBKGND, wParam, lParam); 05274 05275 if (dwEraseCustDraw & CDRF_NOTIFYPOSTERASE) { 05276 ZeroMemory (&tbcd, sizeof(NMTBCUSTOMDRAW)); 05277 tbcd.nmcd.dwDrawStage = CDDS_POSTERASE; 05278 tbcd.nmcd.hdc = (HDC)wParam; 05279 ntfret = TOOLBAR_SendNotify (&tbcd.nmcd.hdr, infoPtr, NM_CUSTOMDRAW); 05280 dwEraseCustDraw = ntfret & 0xffff; 05281 switch (dwEraseCustDraw) 05282 { 05283 case CDRF_DODEFAULT: 05284 break; 05285 case CDRF_SKIPDEFAULT: 05286 return TRUE; 05287 default: 05288 FIXME("[%p] response %d not handled to NM_CUSTOMDRAW (CDDS_POSTERASE)\n", 05289 infoPtr->hwndSelf, ntfret); 05290 } 05291 } 05292 return ret; 05293 } 05294 05295 05296 static inline LRESULT 05297 TOOLBAR_GetFont (const TOOLBAR_INFO *infoPtr) 05298 { 05299 return (LRESULT)infoPtr->hFont; 05300 } 05301 05302 05303 static void 05304 TOOLBAR_SetRelativeHotItem(TOOLBAR_INFO *infoPtr, INT iDirection, DWORD dwReason) 05305 { 05306 INT i; 05307 INT nNewHotItem = infoPtr->nHotItem; 05308 05309 for (i = 0; i < infoPtr->nNumButtons; i++) 05310 { 05311 /* did we wrap? */ 05312 if ((nNewHotItem + iDirection < 0) || 05313 (nNewHotItem + iDirection >= infoPtr->nNumButtons)) 05314 { 05315 NMTBWRAPHOTITEM nmtbwhi; 05316 nmtbwhi.idNew = infoPtr->buttons[nNewHotItem].idCommand; 05317 nmtbwhi.iDirection = iDirection; 05318 nmtbwhi.dwReason = dwReason; 05319 05320 if (TOOLBAR_SendNotify(&nmtbwhi.hdr, infoPtr, TBN_WRAPHOTITEM)) 05321 return; 05322 } 05323 05324 nNewHotItem += iDirection; 05325 nNewHotItem = (nNewHotItem + infoPtr->nNumButtons) % infoPtr->nNumButtons; 05326 05327 if ((infoPtr->buttons[nNewHotItem].fsState & TBSTATE_ENABLED) && 05328 !(infoPtr->buttons[nNewHotItem].fsStyle & BTNS_SEP)) 05329 { 05330 TOOLBAR_SetHotItemEx(infoPtr, nNewHotItem, dwReason); 05331 break; 05332 } 05333 } 05334 } 05335 05336 static LRESULT 05337 TOOLBAR_KeyDown (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05338 { 05339 NMKEY nmkey; 05340 05341 nmkey.nVKey = (UINT)wParam; 05342 nmkey.uFlags = HIWORD(lParam); 05343 05344 if (TOOLBAR_SendNotify(&nmkey.hdr, infoPtr, NM_KEYDOWN)) 05345 return DefWindowProcW(infoPtr->hwndSelf, WM_KEYDOWN, wParam, lParam); 05346 05347 switch ((UINT)wParam) 05348 { 05349 case VK_LEFT: 05350 case VK_UP: 05351 TOOLBAR_SetRelativeHotItem(infoPtr, -1, HICF_ARROWKEYS); 05352 break; 05353 case VK_RIGHT: 05354 case VK_DOWN: 05355 TOOLBAR_SetRelativeHotItem(infoPtr, 1, HICF_ARROWKEYS); 05356 break; 05357 case VK_SPACE: 05358 case VK_RETURN: 05359 if ((infoPtr->nHotItem >= 0) && 05360 (infoPtr->buttons[infoPtr->nHotItem].fsState & TBSTATE_ENABLED)) 05361 { 05362 SendMessageW (infoPtr->hwndNotify, WM_COMMAND, 05363 MAKEWPARAM(infoPtr->buttons[infoPtr->nHotItem].idCommand, BN_CLICKED), 05364 (LPARAM)infoPtr->hwndSelf); 05365 } 05366 break; 05367 } 05368 05369 return 0; 05370 } 05371 05372 05373 static LRESULT 05374 TOOLBAR_LButtonDblClk (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05375 { 05376 POINT pt; 05377 INT nHit; 05378 05379 pt.x = (short)LOWORD(lParam); 05380 pt.y = (short)HIWORD(lParam); 05381 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt); 05382 05383 if (nHit >= 0) 05384 TOOLBAR_LButtonDown (infoPtr, wParam, lParam); 05385 else if (infoPtr->dwStyle & CCS_ADJUSTABLE) 05386 TOOLBAR_Customize (infoPtr); 05387 05388 return 0; 05389 } 05390 05391 05392 static LRESULT 05393 TOOLBAR_LButtonDown (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05394 { 05395 TBUTTON_INFO *btnPtr; 05396 POINT pt; 05397 INT nHit; 05398 NMTOOLBARA nmtb; 05399 NMMOUSE nmmouse; 05400 BOOL bDragKeyPressed; 05401 05402 TRACE("\n"); 05403 05404 if (infoPtr->dwStyle & TBSTYLE_ALTDRAG) 05405 bDragKeyPressed = (GetKeyState(VK_MENU) < 0); 05406 else 05407 bDragKeyPressed = (wParam & MK_SHIFT); 05408 05409 if (infoPtr->hwndToolTip) 05410 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 05411 WM_LBUTTONDOWN, wParam, lParam); 05412 05413 pt.x = (short)LOWORD(lParam); 05414 pt.y = (short)HIWORD(lParam); 05415 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt); 05416 05417 btnPtr = &infoPtr->buttons[nHit]; 05418 05419 if ((nHit >= 0) && bDragKeyPressed && (infoPtr->dwStyle & CCS_ADJUSTABLE)) 05420 { 05421 infoPtr->nButtonDrag = nHit; 05422 SetCapture (infoPtr->hwndSelf); 05423 05424 /* If drag cursor has not been loaded, load it. 05425 * Note: it doesn't need to be freed */ 05426 if (!hCursorDrag) 05427 hCursorDrag = LoadCursorW(COMCTL32_hModule, (LPCWSTR)IDC_MOVEBUTTON); 05428 SetCursor(hCursorDrag); 05429 } 05430 else if (nHit >= 0) 05431 { 05432 RECT arrowRect; 05433 infoPtr->nOldHit = nHit; 05434 05435 CopyRect(&arrowRect, &btnPtr->rect); 05436 arrowRect.left = max(btnPtr->rect.left, btnPtr->rect.right - DDARROW_WIDTH); 05437 05438 /* for EX_DRAWDDARROWS style, click must be in the drop-down arrow rect */ 05439 if ((btnPtr->fsState & TBSTATE_ENABLED) && 05440 ((btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) || 05441 ((btnPtr->fsStyle & BTNS_DROPDOWN) && 05442 ((TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle) && PtInRect(&arrowRect, pt)) || 05443 (!TOOLBAR_HasDropDownArrows(infoPtr->dwExStyle)))))) 05444 { 05445 LRESULT res; 05446 05447 /* draw in pressed state */ 05448 if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) 05449 btnPtr->fsState |= TBSTATE_PRESSED; 05450 else 05451 btnPtr->bDropDownPressed = TRUE; 05452 RedrawWindow(infoPtr->hwndSelf,&btnPtr->rect,0, 05453 RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW); 05454 05455 memset(&nmtb, 0, sizeof(nmtb)); 05456 nmtb.iItem = btnPtr->idCommand; 05457 nmtb.rcButton = btnPtr->rect; 05458 res = TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, 05459 TBN_DROPDOWN); 05460 TRACE("TBN_DROPDOWN responded with %ld\n", res); 05461 05462 if (res != TBDDRET_TREATPRESSED) 05463 { 05464 MSG msg; 05465 05466 /* redraw button in unpressed state */ 05467 if (btnPtr->fsStyle & BTNS_WHOLEDROPDOWN) 05468 btnPtr->fsState &= ~TBSTATE_PRESSED; 05469 else 05470 btnPtr->bDropDownPressed = FALSE; 05471 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 05472 05473 /* find and set hot item 05474 * NOTE: native doesn't do this, but that is a bug */ 05475 GetCursorPos(&pt); 05476 ScreenToClient(infoPtr->hwndSelf, &pt); 05477 nHit = TOOLBAR_InternalHitTest(infoPtr, &pt); 05478 if (!infoPtr->bAnchor || (nHit >= 0)) 05479 TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); 05480 05481 /* remove any left mouse button down or double-click messages 05482 * so that we can get a toggle effect on the button */ 05483 while (PeekMessageW(&msg, infoPtr->hwndSelf, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE) || 05484 PeekMessageW(&msg, infoPtr->hwndSelf, WM_LBUTTONDBLCLK, WM_LBUTTONDBLCLK, PM_REMOVE)) 05485 ; 05486 05487 return 0; 05488 } 05489 /* otherwise drop through and process as pushed */ 05490 } 05491 infoPtr->bCaptured = TRUE; 05492 infoPtr->nButtonDown = nHit; 05493 infoPtr->bDragOutSent = FALSE; 05494 05495 btnPtr->fsState |= TBSTATE_PRESSED; 05496 05497 TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); 05498 05499 if (btnPtr->fsState & TBSTATE_ENABLED) 05500 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 05501 UpdateWindow(infoPtr->hwndSelf); 05502 SetCapture (infoPtr->hwndSelf); 05503 } 05504 05505 if (nHit >=0) 05506 { 05507 memset(&nmtb, 0, sizeof(nmtb)); 05508 nmtb.iItem = btnPtr->idCommand; 05509 TOOLBAR_SendNotify((NMHDR *)&nmtb, infoPtr, TBN_BEGINDRAG); 05510 } 05511 05512 nmmouse.dwHitInfo = nHit; 05513 05514 /* !!! Undocumented - sends NM_LDOWN with the NMMOUSE structure. */ 05515 if (nHit < 0) 05516 nmmouse.dwItemSpec = -1; 05517 else 05518 { 05519 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 05520 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 05521 } 05522 05523 ClientToScreen(infoPtr->hwndSelf, &pt); 05524 nmmouse.pt = pt; 05525 05526 if (!TOOLBAR_SendNotify(&nmmouse.hdr, infoPtr, NM_LDOWN)) 05527 return DefWindowProcW(infoPtr->hwndSelf, WM_LBUTTONDOWN, wParam, lParam); 05528 05529 return 0; 05530 } 05531 05532 static LRESULT 05533 TOOLBAR_LButtonUp (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05534 { 05535 TBUTTON_INFO *btnPtr; 05536 POINT pt; 05537 INT nHit; 05538 INT nOldIndex = -1; 05539 NMHDR hdr; 05540 NMMOUSE nmmouse; 05541 NMTOOLBARA nmtb; 05542 05543 if (infoPtr->hwndToolTip) 05544 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 05545 WM_LBUTTONUP, wParam, lParam); 05546 05547 pt.x = (short)LOWORD(lParam); 05548 pt.y = (short)HIWORD(lParam); 05549 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt); 05550 05551 if (!infoPtr->bAnchor || (nHit >= 0)) 05552 TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); 05553 05554 if (infoPtr->nButtonDrag >= 0) { 05555 RECT rcClient; 05556 NMHDR hdr; 05557 05558 btnPtr = &infoPtr->buttons[infoPtr->nButtonDrag]; 05559 ReleaseCapture(); 05560 /* reset cursor */ 05561 SetCursor(LoadCursorW(NULL, (LPCWSTR)IDC_ARROW)); 05562 05563 GetClientRect(infoPtr->hwndSelf, &rcClient); 05564 if (PtInRect(&rcClient, pt)) 05565 { 05566 INT nButton = -1; 05567 if (nHit >= 0) 05568 nButton = nHit; 05569 else if (nHit < -1) 05570 nButton = -nHit; 05571 else if ((nHit == -1) && PtInRect(&infoPtr->buttons[-nHit].rect, pt)) 05572 nButton = -nHit; 05573 05574 if (nButton == infoPtr->nButtonDrag) 05575 { 05576 /* if the button is moved sightly left and we have a 05577 * separator there then remove it */ 05578 if (pt.x < (btnPtr->rect.left + (btnPtr->rect.right - btnPtr->rect.left)/2)) 05579 { 05580 if ((nButton > 0) && (infoPtr->buttons[nButton-1].fsStyle & BTNS_SEP)) 05581 TOOLBAR_DeleteButton(infoPtr, nButton - 1); 05582 } 05583 else /* else insert a separator before the dragged button */ 05584 { 05585 TBBUTTON tbb; 05586 memset(&tbb, 0, sizeof(tbb)); 05587 tbb.fsStyle = BTNS_SEP; 05588 tbb.iString = -1; 05589 TOOLBAR_InsertButtonT(infoPtr, nButton, &tbb, TRUE); 05590 } 05591 } 05592 else 05593 { 05594 if (nButton == -1) 05595 { 05596 if ((infoPtr->nNumButtons > 0) && (pt.x < infoPtr->buttons[0].rect.left)) 05597 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, 0); 05598 else 05599 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, infoPtr->nNumButtons); 05600 } 05601 else 05602 TOOLBAR_MoveButton(infoPtr, infoPtr->nButtonDrag, nButton); 05603 } 05604 } 05605 else 05606 { 05607 TRACE("button %d dragged out of toolbar\n", infoPtr->nButtonDrag); 05608 TOOLBAR_DeleteButton(infoPtr, infoPtr->nButtonDrag); 05609 } 05610 05611 /* button under cursor changed so need to re-set hot item */ 05612 TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE | HICF_LMOUSE); 05613 infoPtr->nButtonDrag = -1; 05614 05615 TOOLBAR_SendNotify(&hdr, infoPtr, TBN_TOOLBARCHANGE); 05616 } 05617 else if (infoPtr->nButtonDown >= 0) { 05618 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 05619 btnPtr->fsState &= ~TBSTATE_PRESSED; 05620 05621 if (btnPtr->fsStyle & BTNS_CHECK) { 05622 if (btnPtr->fsStyle & BTNS_GROUP) { 05623 nOldIndex = TOOLBAR_GetCheckedGroupButtonIndex (infoPtr, 05624 nHit); 05625 if ((nOldIndex != nHit) && 05626 (nOldIndex != -1)) 05627 infoPtr->buttons[nOldIndex].fsState &= ~TBSTATE_CHECKED; 05628 btnPtr->fsState |= TBSTATE_CHECKED; 05629 } 05630 else { 05631 if (btnPtr->fsState & TBSTATE_CHECKED) 05632 btnPtr->fsState &= ~TBSTATE_CHECKED; 05633 else 05634 btnPtr->fsState |= TBSTATE_CHECKED; 05635 } 05636 } 05637 05638 if (nOldIndex != -1) 05639 InvalidateRect(infoPtr->hwndSelf, &infoPtr->buttons[nOldIndex].rect, TRUE); 05640 05641 /* 05642 * now we can ReleaseCapture, which triggers CAPTURECHANGED msg, 05643 * that resets bCaptured and btn TBSTATE_PRESSED flags, 05644 * and obliterates nButtonDown and nOldHit (see TOOLBAR_CaptureChanged) 05645 */ 05646 if ((infoPtr->bCaptured) && (infoPtr->nButtonDown >= 0)) 05647 ReleaseCapture (); 05648 infoPtr->nButtonDown = -1; 05649 05650 /* Issue NM_RELEASEDCAPTURE to parent to let him know it is released */ 05651 TOOLBAR_SendNotify (&hdr, infoPtr, 05652 NM_RELEASEDCAPTURE); 05653 05654 /* native issues TBN_ENDDRAG here, if _LBUTTONDOWN issued the 05655 * TBN_BEGINDRAG 05656 */ 05657 memset(&nmtb, 0, sizeof(nmtb)); 05658 nmtb.iItem = btnPtr->idCommand; 05659 TOOLBAR_SendNotify ((NMHDR *) &nmtb, infoPtr, 05660 TBN_ENDDRAG); 05661 05662 if (btnPtr->fsState & TBSTATE_ENABLED) 05663 { 05664 SendMessageW (infoPtr->hwndNotify, WM_COMMAND, 05665 MAKEWPARAM(infoPtr->buttons[nHit].idCommand, BN_CLICKED), (LPARAM)infoPtr->hwndSelf); 05666 05667 /* In case we have just been destroyed... */ 05668 if(!IsWindow(infoPtr->hwndSelf)) 05669 return 0; 05670 } 05671 } 05672 05673 /* !!! Undocumented - toolbar at 4.71 level and above sends 05674 * NM_CLICK with the NMMOUSE structure. */ 05675 nmmouse.dwHitInfo = nHit; 05676 05677 if (nHit < 0) 05678 nmmouse.dwItemSpec = -1; 05679 else 05680 { 05681 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 05682 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 05683 } 05684 05685 ClientToScreen(infoPtr->hwndSelf, &pt); 05686 nmmouse.pt = pt; 05687 05688 if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_CLICK)) 05689 return DefWindowProcW(infoPtr->hwndSelf, WM_LBUTTONUP, wParam, lParam); 05690 05691 return 0; 05692 } 05693 05694 static LRESULT 05695 TOOLBAR_RButtonUp(TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05696 { 05697 INT nHit; 05698 NMMOUSE nmmouse; 05699 POINT pt; 05700 05701 pt.x = (short)LOWORD(lParam); 05702 pt.y = (short)HIWORD(lParam); 05703 05704 nHit = TOOLBAR_InternalHitTest(infoPtr, &pt); 05705 nmmouse.dwHitInfo = nHit; 05706 05707 if (nHit < 0) { 05708 nmmouse.dwItemSpec = -1; 05709 } else { 05710 nmmouse.dwItemSpec = infoPtr->buttons[nmmouse.dwHitInfo].idCommand; 05711 nmmouse.dwItemData = infoPtr->buttons[nmmouse.dwHitInfo].dwData; 05712 } 05713 05714 ClientToScreen(infoPtr->hwndSelf, &pt); 05715 nmmouse.pt = pt; 05716 05717 if (!TOOLBAR_SendNotify((LPNMHDR)&nmmouse, infoPtr, NM_RCLICK)) 05718 return DefWindowProcW(infoPtr->hwndSelf, WM_RBUTTONUP, wParam, lParam); 05719 05720 return 0; 05721 } 05722 05723 static LRESULT 05724 TOOLBAR_RButtonDblClk( TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05725 { 05726 NMHDR nmhdr; 05727 05728 if (!TOOLBAR_SendNotify(&nmhdr, infoPtr, NM_RDBLCLK)) 05729 return DefWindowProcW(infoPtr->hwndSelf, WM_RBUTTONDBLCLK, wParam, lParam); 05730 05731 return 0; 05732 } 05733 05734 static LRESULT 05735 TOOLBAR_CaptureChanged(TOOLBAR_INFO *infoPtr) 05736 { 05737 TBUTTON_INFO *btnPtr; 05738 05739 infoPtr->bCaptured = FALSE; 05740 05741 if (infoPtr->nButtonDown >= 0) 05742 { 05743 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 05744 btnPtr->fsState &= ~TBSTATE_PRESSED; 05745 05746 infoPtr->nOldHit = -1; 05747 05748 if (btnPtr->fsState & TBSTATE_ENABLED) 05749 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 05750 } 05751 return 0; 05752 } 05753 05754 static LRESULT 05755 TOOLBAR_MouseLeave (TOOLBAR_INFO *infoPtr) 05756 { 05757 /* don't remove hot effects when in anchor highlighting mode or when a 05758 * drop-down button is pressed */ 05759 if (infoPtr->nHotItem >= 0 && !infoPtr->bAnchor) 05760 { 05761 TBUTTON_INFO *hotBtnPtr = &infoPtr->buttons[infoPtr->nHotItem]; 05762 if (!hotBtnPtr->bDropDownPressed) 05763 TOOLBAR_SetHotItemEx(infoPtr, TOOLBAR_NOWHERE, HICF_MOUSE); 05764 } 05765 05766 if (infoPtr->nOldHit < 0) 05767 return TRUE; 05768 05769 /* If the last button we were over is depressed then make it not */ 05770 /* depressed and redraw it */ 05771 if(infoPtr->nOldHit == infoPtr->nButtonDown) 05772 { 05773 TBUTTON_INFO *btnPtr; 05774 RECT rc1; 05775 05776 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 05777 05778 btnPtr->fsState &= ~TBSTATE_PRESSED; 05779 05780 rc1 = btnPtr->rect; 05781 InflateRect (&rc1, 1, 1); 05782 InvalidateRect (infoPtr->hwndSelf, &rc1, TRUE); 05783 } 05784 05785 if (infoPtr->bCaptured && !infoPtr->bDragOutSent) 05786 { 05787 NMTOOLBARW nmt; 05788 ZeroMemory(&nmt, sizeof(nmt)); 05789 nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; 05790 TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); 05791 infoPtr->bDragOutSent = TRUE; 05792 } 05793 05794 infoPtr->nOldHit = -1; /* reset the old hit index as we've left the toolbar */ 05795 05796 return TRUE; 05797 } 05798 05799 static LRESULT 05800 TOOLBAR_MouseMove (TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 05801 { 05802 POINT pt; 05803 TRACKMOUSEEVENT trackinfo; 05804 INT nHit; 05805 TBUTTON_INFO *btnPtr; 05806 05807 if ((infoPtr->dwStyle & TBSTYLE_TOOLTIPS) && (infoPtr->hwndToolTip == NULL)) 05808 TOOLBAR_TooltipCreateControl(infoPtr); 05809 05810 if ((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) { 05811 /* fill in the TRACKMOUSEEVENT struct */ 05812 trackinfo.cbSize = sizeof(TRACKMOUSEEVENT); 05813 trackinfo.dwFlags = TME_QUERY; 05814 05815 /* call _TrackMouseEvent to see if we are currently tracking for this hwnd */ 05816 _TrackMouseEvent(&trackinfo); 05817 05818 /* Make sure tracking is enabled so we receive a WM_MOUSELEAVE message */ 05819 if(trackinfo.hwndTrack != infoPtr->hwndSelf || !(trackinfo.dwFlags & TME_LEAVE)) { 05820 trackinfo.dwFlags = TME_LEAVE; /* notify upon leaving */ 05821 trackinfo.hwndTrack = infoPtr->hwndSelf; 05822 05823 /* call TRACKMOUSEEVENT so we receive a WM_MOUSELEAVE message */ 05824 /* and can properly deactivate the hot toolbar button */ 05825 _TrackMouseEvent(&trackinfo); 05826 } 05827 } 05828 05829 if (infoPtr->hwndToolTip) 05830 TOOLBAR_RelayEvent (infoPtr->hwndToolTip, infoPtr->hwndSelf, 05831 WM_MOUSEMOVE, wParam, lParam); 05832 05833 pt.x = (short)LOWORD(lParam); 05834 pt.y = (short)HIWORD(lParam); 05835 05836 nHit = TOOLBAR_InternalHitTest (infoPtr, &pt); 05837 05838 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 05839 && (!infoPtr->bAnchor || (nHit >= 0))) 05840 TOOLBAR_SetHotItemEx(infoPtr, nHit, HICF_MOUSE); 05841 05842 if (infoPtr->nOldHit != nHit) 05843 { 05844 if (infoPtr->bCaptured) 05845 { 05846 if (!infoPtr->bDragOutSent) 05847 { 05848 NMTOOLBARW nmt; 05849 ZeroMemory(&nmt, sizeof(nmt)); 05850 nmt.iItem = infoPtr->buttons[infoPtr->nButtonDown].idCommand; 05851 TOOLBAR_SendNotify(&nmt.hdr, infoPtr, TBN_DRAGOUT); 05852 infoPtr->bDragOutSent = TRUE; 05853 } 05854 05855 btnPtr = &infoPtr->buttons[infoPtr->nButtonDown]; 05856 if (infoPtr->nOldHit == infoPtr->nButtonDown) { 05857 btnPtr->fsState &= ~TBSTATE_PRESSED; 05858 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 05859 } 05860 else if (nHit == infoPtr->nButtonDown) { 05861 btnPtr->fsState |= TBSTATE_PRESSED; 05862 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 05863 } 05864 infoPtr->nOldHit = nHit; 05865 } 05866 } 05867 05868 return 0; 05869 } 05870 05871 05872 static inline LRESULT 05873 TOOLBAR_NCActivate (HWND hwnd, WPARAM wParam, LPARAM lParam) 05874 { 05875 /* if (wndPtr->dwStyle & CCS_NODIVIDER) */ 05876 return DefWindowProcW (hwnd, WM_NCACTIVATE, wParam, lParam); 05877 /* else */ 05878 /* return TOOLBAR_NCPaint (wndPtr, wParam, lParam); */ 05879 } 05880 05881 05882 static inline LRESULT 05883 TOOLBAR_NCCalcSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 05884 { 05885 if (!(GetWindowLongW(hwnd, GWL_STYLE) & CCS_NODIVIDER)) 05886 ((LPRECT)lParam)->top += GetSystemMetrics(SM_CYEDGE); 05887 05888 return DefWindowProcW (hwnd, WM_NCCALCSIZE, wParam, lParam); 05889 } 05890 05891 05892 static LRESULT 05893 TOOLBAR_NCCreate (HWND hwnd, WPARAM wParam, const CREATESTRUCTW *lpcs) 05894 { 05895 TOOLBAR_INFO *infoPtr; 05896 DWORD styleadd = 0; 05897 05898 /* allocate memory for info structure */ 05899 infoPtr = Alloc (sizeof(TOOLBAR_INFO)); 05900 SetWindowLongPtrW (hwnd, 0, (LONG_PTR)infoPtr); 05901 05902 /* paranoid!! */ 05903 infoPtr->dwStructSize = sizeof(TBBUTTON); 05904 infoPtr->nRows = 1; 05905 infoPtr->nWidth = 0; 05906 05907 /* initialize info structure */ 05908 infoPtr->nButtonWidth = 23; 05909 infoPtr->nButtonHeight = 22; 05910 infoPtr->nBitmapHeight = 16; 05911 infoPtr->nBitmapWidth = 16; 05912 05913 infoPtr->nMaxTextRows = 1; 05914 infoPtr->cxMin = -1; 05915 infoPtr->cxMax = -1; 05916 infoPtr->nNumBitmaps = 0; 05917 infoPtr->nNumStrings = 0; 05918 05919 infoPtr->bCaptured = FALSE; 05920 infoPtr->nButtonDown = -1; 05921 infoPtr->nButtonDrag = -1; 05922 infoPtr->nOldHit = -1; 05923 infoPtr->nHotItem = -1; 05924 infoPtr->hwndNotify = lpcs->hwndParent; 05925 infoPtr->dwDTFlags = (lpcs->style & TBSTYLE_LIST) ? DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS: DT_CENTER | DT_END_ELLIPSIS; 05926 infoPtr->bAnchor = FALSE; /* no anchor highlighting */ 05927 infoPtr->bDragOutSent = FALSE; 05928 infoPtr->iVersion = 0; 05929 infoPtr->hwndSelf = hwnd; 05930 infoPtr->bDoRedraw = TRUE; 05931 infoPtr->clrBtnHighlight = CLR_DEFAULT; 05932 infoPtr->clrBtnShadow = CLR_DEFAULT; 05933 infoPtr->szPadding.cx = DEFPAD_CX; 05934 infoPtr->szPadding.cy = DEFPAD_CY; 05935 infoPtr->iListGap = DEFLISTGAP; 05936 infoPtr->iTopMargin = default_top_margin(infoPtr); 05937 infoPtr->dwStyle = lpcs->style; 05938 infoPtr->tbim.iButton = -1; 05939 05940 /* fix instance handle, if the toolbar was created by CreateToolbarEx() */ 05941 if (!GetWindowLongPtrW (hwnd, GWLP_HINSTANCE)) { 05942 HINSTANCE hInst = (HINSTANCE)GetWindowLongPtrW (GetParent (hwnd), GWLP_HINSTANCE); 05943 SetWindowLongPtrW (hwnd, GWLP_HINSTANCE, (LONG_PTR)hInst); 05944 } 05945 05946 /* native control does: 05947 * Get a lot of colors and brushes 05948 * WM_NOTIFYFORMAT 05949 * SystemParametersInfoW(0x1f, 0x3c, adr1, 0) 05950 * CreateFontIndirectW(adr1) 05951 * CreateBitmap(0x27, 0x24, 1, 1, 0) 05952 * hdc = GetDC(toolbar) 05953 * GetSystemMetrics(0x48) 05954 * fnt2=CreateFontW(0xe, 0, 0, 0, 0x190, 0, 0, 0, 0, 2, 05955 * 0, 0, 0, 0, "MARLETT") 05956 * oldfnt = SelectObject(hdc, fnt2) 05957 * GetCharWidthW(hdc, 0x36, 0x36, adr2) 05958 * GetTextMetricsW(hdc, adr3) 05959 * SelectObject(hdc, oldfnt) 05960 * DeleteObject(fnt2) 05961 * ReleaseDC(hdc) 05962 * InvalidateRect(toolbar, 0, 1) 05963 * SetWindowLongW(toolbar, 0, addr) 05964 * SetWindowLongW(toolbar, -16, xxx) **sometimes** 05965 * WM_STYLECHANGING 05966 * CallWinEx old new 05967 * ie 1 0x56000a4c 0x46000a4c 0x56008a4d 05968 * ie 2 0x4600094c 0x4600094c 0x4600894d 05969 * ie 3 0x56000b4c 0x46000b4c 0x56008b4d 05970 * rebar 0x50008844 0x40008844 0x50008845 05971 * pager 0x50000844 0x40000844 0x50008845 05972 * IC35mgr 0x5400084e **nochange** 05973 * on entry to _NCCREATE 0x5400084e 05974 * rowlist 0x5400004e **nochange** 05975 * on entry to _NCCREATE 0x5400004e 05976 * 05977 */ 05978 05979 /* I think the code below is a bug, but it is the way that the native 05980 * controls seem to work. The effect is that if the user of TBSTYLE_FLAT 05981 * forgets to specify TBSTYLE_TRANSPARENT but does specify either 05982 * CCS_TOP or CCS_BOTTOM (_NOMOVEY and _TOP), then the control 05983 * does *not* set TBSTYLE_TRANSPARENT even though it should!!!! 05984 * Somehow, the only cases of this seem to be MFC programs. 05985 * 05986 * Note also that the addition of _TRANSPARENT occurs *only* here. It 05987 * does not occur in the WM_STYLECHANGING routine. 05988 * (Guy Albertelli 9/2001) 05989 * 05990 */ 05991 if (((infoPtr->dwStyle & TBSTYLE_FLAT) || GetWindowTheme (infoPtr->hwndSelf)) 05992 && !(lpcs->style & TBSTYLE_TRANSPARENT)) 05993 styleadd |= TBSTYLE_TRANSPARENT; 05994 if (!(lpcs->style & (CCS_TOP | CCS_NOMOVEY))) { 05995 styleadd |= CCS_TOP; /* default to top */ 05996 SetWindowLongW (hwnd, GWL_STYLE, lpcs->style | styleadd); 05997 } 05998 05999 return DefWindowProcW (hwnd, WM_NCCREATE, wParam, (LPARAM)lpcs); 06000 } 06001 06002 06003 static LRESULT 06004 TOOLBAR_NCPaint (HWND hwnd, WPARAM wParam, LPARAM lParam) 06005 { 06006 DWORD dwStyle = GetWindowLongW(hwnd, GWL_STYLE); 06007 RECT rcWindow; 06008 HDC hdc; 06009 06010 if (dwStyle & WS_MINIMIZE) 06011 return 0; /* Nothing to do */ 06012 06013 DefWindowProcW (hwnd, WM_NCPAINT, wParam, lParam); 06014 06015 if (!(hdc = GetDCEx (hwnd, 0, DCX_USESTYLE | DCX_WINDOW))) 06016 return 0; 06017 06018 if (!(dwStyle & CCS_NODIVIDER)) 06019 { 06020 GetWindowRect (hwnd, &rcWindow); 06021 OffsetRect (&rcWindow, -rcWindow.left, -rcWindow.top); 06022 if( dwStyle & WS_BORDER ) 06023 InflateRect (&rcWindow, -1, -1); 06024 DrawEdge (hdc, &rcWindow, EDGE_ETCHED, BF_TOP); 06025 } 06026 06027 ReleaseDC( hwnd, hdc ); 06028 06029 return 0; 06030 } 06031 06032 06033 /* handles requests from the tooltip control on what text to display */ 06034 static LRESULT TOOLBAR_TTGetDispInfo (TOOLBAR_INFO *infoPtr, NMTTDISPINFOW *lpnmtdi) 06035 { 06036 int index = TOOLBAR_GetButtonIndex(infoPtr, lpnmtdi->hdr.idFrom, FALSE); 06037 06038 TRACE("button index = %d\n", index); 06039 06040 Free (infoPtr->pszTooltipText); 06041 infoPtr->pszTooltipText = NULL; 06042 06043 if (index < 0) 06044 return 0; 06045 06046 if (infoPtr->bUnicode) 06047 { 06048 WCHAR wszBuffer[INFOTIPSIZE+1]; 06049 NMTBGETINFOTIPW tbgit; 06050 unsigned int len; /* in chars */ 06051 06052 wszBuffer[0] = '\0'; 06053 wszBuffer[INFOTIPSIZE] = '\0'; 06054 06055 tbgit.pszText = wszBuffer; 06056 tbgit.cchTextMax = INFOTIPSIZE; 06057 tbgit.iItem = lpnmtdi->hdr.idFrom; 06058 tbgit.lParam = infoPtr->buttons[index].dwData; 06059 06060 TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPW); 06061 06062 TRACE("TBN_GETINFOTIPW - got string %s\n", debugstr_w(tbgit.pszText)); 06063 06064 len = strlenW(tbgit.pszText); 06065 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) 06066 { 06067 /* need to allocate temporary buffer in infoPtr as there 06068 * isn't enough space in buffer passed to us by the 06069 * tooltip control */ 06070 infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); 06071 if (infoPtr->pszTooltipText) 06072 { 06073 memcpy(infoPtr->pszTooltipText, tbgit.pszText, (len+1)*sizeof(WCHAR)); 06074 lpnmtdi->lpszText = infoPtr->pszTooltipText; 06075 return 0; 06076 } 06077 } 06078 else if (len > 0) 06079 { 06080 memcpy(lpnmtdi->lpszText, tbgit.pszText, (len+1)*sizeof(WCHAR)); 06081 return 0; 06082 } 06083 } 06084 else 06085 { 06086 CHAR szBuffer[INFOTIPSIZE+1]; 06087 NMTBGETINFOTIPA tbgit; 06088 unsigned int len; /* in chars */ 06089 06090 szBuffer[0] = '\0'; 06091 szBuffer[INFOTIPSIZE] = '\0'; 06092 06093 tbgit.pszText = szBuffer; 06094 tbgit.cchTextMax = INFOTIPSIZE; 06095 tbgit.iItem = lpnmtdi->hdr.idFrom; 06096 tbgit.lParam = infoPtr->buttons[index].dwData; 06097 06098 TOOLBAR_SendNotify(&tbgit.hdr, infoPtr, TBN_GETINFOTIPA); 06099 06100 TRACE("TBN_GETINFOTIPA - got string %s\n", debugstr_a(tbgit.pszText)); 06101 06102 len = MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, NULL, 0); 06103 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])) 06104 { 06105 /* need to allocate temporary buffer in infoPtr as there 06106 * isn't enough space in buffer passed to us by the 06107 * tooltip control */ 06108 infoPtr->pszTooltipText = Alloc(len*sizeof(WCHAR)); 06109 if (infoPtr->pszTooltipText) 06110 { 06111 MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, infoPtr->pszTooltipText, len); 06112 lpnmtdi->lpszText = infoPtr->pszTooltipText; 06113 return 0; 06114 } 06115 } 06116 else if (tbgit.pszText && tbgit.pszText[0]) 06117 { 06118 MultiByteToWideChar(CP_ACP, 0, tbgit.pszText, -1, 06119 lpnmtdi->lpszText, sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])); 06120 return 0; 06121 } 06122 } 06123 06124 /* if button has text, but it is not shown then automatically 06125 * use that text as tooltip */ 06126 if ((infoPtr->dwExStyle & TBSTYLE_EX_MIXEDBUTTONS) && 06127 !(infoPtr->buttons[index].fsStyle & BTNS_SHOWTEXT)) 06128 { 06129 LPWSTR pszText = TOOLBAR_GetText(infoPtr, &infoPtr->buttons[index]); 06130 unsigned int len = pszText ? strlenW(pszText) : 0; 06131 06132 TRACE("using button hidden text %s\n", debugstr_w(pszText)); 06133 06134 if (len > sizeof(lpnmtdi->szText)/sizeof(lpnmtdi->szText[0])-1) 06135 { 06136 /* need to allocate temporary buffer in infoPtr as there 06137 * isn't enough space in buffer passed to us by the 06138 * tooltip control */ 06139 infoPtr->pszTooltipText = Alloc((len+1)*sizeof(WCHAR)); 06140 if (infoPtr->pszTooltipText) 06141 { 06142 memcpy(infoPtr->pszTooltipText, pszText, (len+1)*sizeof(WCHAR)); 06143 lpnmtdi->lpszText = infoPtr->pszTooltipText; 06144 return 0; 06145 } 06146 } 06147 else if (len > 0) 06148 { 06149 memcpy(lpnmtdi->lpszText, pszText, (len+1)*sizeof(WCHAR)); 06150 return 0; 06151 } 06152 } 06153 06154 TRACE("Sending tooltip notification to %p\n", infoPtr->hwndNotify); 06155 06156 /* last resort: send notification on to app */ 06157 /* FIXME: find out what is really used here */ 06158 return SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, lpnmtdi->hdr.idFrom, (LPARAM)lpnmtdi); 06159 } 06160 06161 06162 static inline LRESULT 06163 TOOLBAR_Notify (TOOLBAR_INFO *infoPtr, LPNMHDR lpnmh) 06164 { 06165 switch (lpnmh->code) 06166 { 06167 case PGN_CALCSIZE: 06168 { 06169 LPNMPGCALCSIZE lppgc = (LPNMPGCALCSIZE)lpnmh; 06170 06171 if (lppgc->dwFlag == PGF_CALCWIDTH) { 06172 lppgc->iWidth = infoPtr->rcBound.right - infoPtr->rcBound.left; 06173 TRACE("processed PGN_CALCSIZE, returning horz size = %d\n", 06174 lppgc->iWidth); 06175 } 06176 else { 06177 lppgc->iHeight = infoPtr->rcBound.bottom - infoPtr->rcBound.top; 06178 TRACE("processed PGN_CALCSIZE, returning vert size = %d\n", 06179 lppgc->iHeight); 06180 } 06181 return 0; 06182 } 06183 06184 case PGN_SCROLL: 06185 { 06186 LPNMPGSCROLL lppgs = (LPNMPGSCROLL)lpnmh; 06187 06188 lppgs->iScroll = (lppgs->iDir & (PGF_SCROLLLEFT | PGF_SCROLLRIGHT)) ? 06189 infoPtr->nButtonWidth : infoPtr->nButtonHeight; 06190 TRACE("processed PGN_SCROLL, returning scroll=%d, dir=%d\n", 06191 lppgs->iScroll, lppgs->iDir); 06192 return 0; 06193 } 06194 06195 case TTN_GETDISPINFOW: 06196 return TOOLBAR_TTGetDispInfo(infoPtr, (LPNMTTDISPINFOW)lpnmh); 06197 06198 case TTN_GETDISPINFOA: 06199 FIXME("TTN_GETDISPINFOA - should not be received; please report\n"); 06200 return 0; 06201 06202 default: 06203 return 0; 06204 } 06205 } 06206 06207 06208 static LRESULT 06209 TOOLBAR_NotifyFormat(const TOOLBAR_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 06210 { 06211 LRESULT format; 06212 06213 TRACE("wParam = 0x%lx, lParam = 0x%08lx\n", wParam, lParam); 06214 06215 if (lParam == NF_QUERY) 06216 return NFR_UNICODE; 06217 06218 if (lParam == NF_REQUERY) { 06219 format = SendMessageW(infoPtr->hwndNotify, 06220 WM_NOTIFYFORMAT, (WPARAM)infoPtr->hwndSelf, NF_QUERY); 06221 if ((format != NFR_ANSI) && (format != NFR_UNICODE)) { 06222 ERR("wrong response to WM_NOTIFYFORMAT (%ld), assuming ANSI\n", 06223 format); 06224 format = NFR_ANSI; 06225 } 06226 return format; 06227 } 06228 return 0; 06229 } 06230 06231 06232 static LRESULT 06233 TOOLBAR_Paint (TOOLBAR_INFO *infoPtr, WPARAM wParam) 06234 { 06235 HDC hdc; 06236 PAINTSTRUCT ps; 06237 06238 /* fill ps.rcPaint with a default rect */ 06239 ps.rcPaint = infoPtr->rcBound; 06240 06241 hdc = wParam==0 ? BeginPaint(infoPtr->hwndSelf, &ps) : (HDC)wParam; 06242 06243 TRACE("psrect=(%s)\n", wine_dbgstr_rect(&ps.rcPaint)); 06244 06245 TOOLBAR_Refresh (infoPtr, hdc, &ps); 06246 if (!wParam) EndPaint (infoPtr->hwndSelf, &ps); 06247 06248 return 0; 06249 } 06250 06251 06252 static LRESULT 06253 TOOLBAR_SetFocus (TOOLBAR_INFO *infoPtr) 06254 { 06255 TRACE("nHotItem = %d\n", infoPtr->nHotItem); 06256 06257 /* make first item hot */ 06258 if (infoPtr->nNumButtons > 0) 06259 TOOLBAR_SetHotItemEx(infoPtr, 0, HICF_OTHER); 06260 06261 return 0; 06262 } 06263 06264 static LRESULT 06265 TOOLBAR_SetFont(TOOLBAR_INFO *infoPtr, HFONT hFont, WORD Redraw) 06266 { 06267 TRACE("font=%p redraw=%d\n", hFont, Redraw); 06268 06269 if (hFont == 0) 06270 infoPtr->hFont = infoPtr->hDefaultFont; 06271 else 06272 infoPtr->hFont = hFont; 06273 06274 TOOLBAR_CalcToolbar(infoPtr); 06275 06276 if (Redraw) 06277 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 06278 return 1; 06279 } 06280 06281 static LRESULT 06282 TOOLBAR_SetRedraw (TOOLBAR_INFO *infoPtr, WPARAM wParam) 06283 /***************************************************** 06284 * 06285 * Function; 06286 * Handles the WM_SETREDRAW message. 06287 * 06288 * Documentation: 06289 * According to testing V4.71 of COMCTL32 returns the 06290 * *previous* status of the redraw flag (either 0 or 1) 06291 * instead of the MSDN documented value of 0 if handled. 06292 * (For laughs see the "consistency" with same function 06293 * in rebar.) 06294 * 06295 *****************************************************/ 06296 { 06297 BOOL oldredraw = infoPtr->bDoRedraw; 06298 06299 TRACE("set to %s\n", 06300 (wParam) ? "TRUE" : "FALSE"); 06301 infoPtr->bDoRedraw = (BOOL) wParam; 06302 if (wParam) { 06303 InvalidateRect (infoPtr->hwndSelf, 0, TRUE); 06304 } 06305 return (oldredraw) ? 1 : 0; 06306 } 06307 06308 06309 static LRESULT 06310 TOOLBAR_Size (TOOLBAR_INFO *infoPtr) 06311 { 06312 TRACE("sizing toolbar!\n"); 06313 06314 if (infoPtr->dwExStyle & TBSTYLE_EX_HIDECLIPPEDBUTTONS) 06315 { 06316 RECT delta_width, delta_height, client, dummy; 06317 DWORD min_x, max_x, min_y, max_y; 06318 TBUTTON_INFO *btnPtr; 06319 INT i; 06320 06321 GetClientRect(infoPtr->hwndSelf, &client); 06322 if(client.right > infoPtr->client_rect.right) 06323 { 06324 min_x = infoPtr->client_rect.right; 06325 max_x = client.right; 06326 } 06327 else 06328 { 06329 max_x = infoPtr->client_rect.right; 06330 min_x = client.right; 06331 } 06332 if(client.bottom > infoPtr->client_rect.bottom) 06333 { 06334 min_y = infoPtr->client_rect.bottom; 06335 max_y = client.bottom; 06336 } 06337 else 06338 { 06339 max_y = infoPtr->client_rect.bottom; 06340 min_y = client.bottom; 06341 } 06342 06343 SetRect(&delta_width, min_x, 0, max_x, min_y); 06344 SetRect(&delta_height, 0, min_y, max_x, max_y); 06345 06346 TRACE("delta_width %s delta_height %s\n", wine_dbgstr_rect(&delta_width), wine_dbgstr_rect(&delta_height)); 06347 btnPtr = infoPtr->buttons; 06348 for (i = 0; i < infoPtr->nNumButtons; i++, btnPtr++) 06349 if(IntersectRect(&dummy, &delta_width, &btnPtr->rect) || 06350 IntersectRect(&dummy, &delta_height, &btnPtr->rect)) 06351 InvalidateRect(infoPtr->hwndSelf, &btnPtr->rect, TRUE); 06352 } 06353 GetClientRect(infoPtr->hwndSelf, &infoPtr->client_rect); 06354 TOOLBAR_AutoSize(infoPtr); 06355 return 0; 06356 } 06357 06358 06359 static LRESULT 06360 TOOLBAR_StyleChanged (TOOLBAR_INFO *infoPtr, INT nType, const STYLESTRUCT *lpStyle) 06361 { 06362 if (nType == GWL_STYLE) 06363 { 06364 DWORD dwOldStyle = infoPtr->dwStyle; 06365 06366 if (lpStyle->styleNew & TBSTYLE_LIST) 06367 infoPtr->dwDTFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS; 06368 else 06369 infoPtr->dwDTFlags = DT_CENTER | DT_END_ELLIPSIS; 06370 06371 TRACE("new style 0x%08x\n", lpStyle->styleNew); 06372 06373 infoPtr->dwStyle = lpStyle->styleNew; 06374 TOOLBAR_CheckStyle (infoPtr); 06375 06376 if ((dwOldStyle ^ lpStyle->styleNew) & (TBSTYLE_WRAPABLE | CCS_VERT)) 06377 TOOLBAR_LayoutToolbar(infoPtr); 06378 06379 /* only resize if one of the CCS_* styles was changed */ 06380 if ((dwOldStyle ^ lpStyle->styleNew) & COMMON_STYLES) 06381 { 06382 TOOLBAR_AutoSize (infoPtr); 06383 06384 InvalidateRect(infoPtr->hwndSelf, NULL, TRUE); 06385 } 06386 } 06387 06388 return 0; 06389 } 06390 06391 06392 static LRESULT 06393 TOOLBAR_SysColorChange (void) 06394 { 06395 COMCTL32_RefreshSysColors(); 06396 06397 return 0; 06398 } 06399 06400 06401 /* update theme after a WM_THEMECHANGED message */ 06402 static LRESULT theme_changed (HWND hwnd) 06403 { 06404 HTHEME theme = GetWindowTheme (hwnd); 06405 CloseThemeData (theme); 06406 OpenThemeData (hwnd, themeClass); 06407 return 0; 06408 } 06409 06410 06411 static LRESULT WINAPI 06412 ToolbarWindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 06413 { 06414 TOOLBAR_INFO *infoPtr = (TOOLBAR_INFO *)GetWindowLongPtrW(hwnd, 0); 06415 06416 TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", 06417 hwnd, uMsg, /* SPY_GetMsgName(uMsg), */ wParam, lParam); 06418 06419 if (!infoPtr && (uMsg != WM_NCCREATE)) 06420 return DefWindowProcW( hwnd, uMsg, wParam, lParam ); 06421 06422 switch (uMsg) 06423 { 06424 case TB_ADDBITMAP: 06425 return TOOLBAR_AddBitmap (infoPtr, (INT)wParam, (TBADDBITMAP*)lParam); 06426 06427 case TB_ADDBUTTONSA: 06428 case TB_ADDBUTTONSW: 06429 return TOOLBAR_AddButtonsT (infoPtr, wParam, (LPTBBUTTON)lParam, 06430 uMsg == TB_ADDBUTTONSW); 06431 case TB_ADDSTRINGA: 06432 return TOOLBAR_AddStringA (infoPtr, (HINSTANCE)wParam, lParam); 06433 06434 case TB_ADDSTRINGW: 06435 return TOOLBAR_AddStringW (infoPtr, (HINSTANCE)wParam, lParam); 06436 06437 case TB_AUTOSIZE: 06438 return TOOLBAR_AutoSize (infoPtr); 06439 06440 case TB_BUTTONCOUNT: 06441 return TOOLBAR_ButtonCount (infoPtr); 06442 06443 case TB_BUTTONSTRUCTSIZE: 06444 return TOOLBAR_ButtonStructSize (infoPtr, wParam); 06445 06446 case TB_CHANGEBITMAP: 06447 return TOOLBAR_ChangeBitmap (infoPtr, wParam, LOWORD(lParam)); 06448 06449 case TB_CHECKBUTTON: 06450 return TOOLBAR_CheckButton (infoPtr, wParam, lParam); 06451 06452 case TB_COMMANDTOINDEX: 06453 return TOOLBAR_CommandToIndex (infoPtr, wParam); 06454 06455 case TB_CUSTOMIZE: 06456 return TOOLBAR_Customize (infoPtr); 06457 06458 case TB_DELETEBUTTON: 06459 return TOOLBAR_DeleteButton (infoPtr, wParam); 06460 06461 case TB_ENABLEBUTTON: 06462 return TOOLBAR_EnableButton (infoPtr, wParam, lParam); 06463 06464 case TB_GETANCHORHIGHLIGHT: 06465 return TOOLBAR_GetAnchorHighlight (infoPtr); 06466 06467 case TB_GETBITMAP: 06468 return TOOLBAR_GetBitmap (infoPtr, wParam); 06469 06470 case TB_GETBITMAPFLAGS: 06471 return TOOLBAR_GetBitmapFlags (); 06472 06473 case TB_GETBUTTON: 06474 return TOOLBAR_GetButton (infoPtr, wParam, (TBBUTTON*)lParam); 06475 06476 case TB_GETBUTTONINFOA: 06477 case TB_GETBUTTONINFOW: 06478 return TOOLBAR_GetButtonInfoT (infoPtr, wParam, (LPTBBUTTONINFOW)lParam, 06479 uMsg == TB_GETBUTTONINFOW); 06480 case TB_GETBUTTONSIZE: 06481 return TOOLBAR_GetButtonSize (infoPtr); 06482 06483 case TB_GETBUTTONTEXTA: 06484 case TB_GETBUTTONTEXTW: 06485 return TOOLBAR_GetButtonText (infoPtr, wParam, (LPWSTR)lParam, 06486 uMsg == TB_GETBUTTONTEXTW); 06487 06488 case TB_GETDISABLEDIMAGELIST: 06489 return TOOLBAR_GetDisabledImageList (infoPtr, wParam); 06490 06491 case TB_GETEXTENDEDSTYLE: 06492 return TOOLBAR_GetExtendedStyle (infoPtr); 06493 06494 case TB_GETHOTIMAGELIST: 06495 return TOOLBAR_GetHotImageList (infoPtr, wParam); 06496 06497 case TB_GETHOTITEM: 06498 return TOOLBAR_GetHotItem (infoPtr); 06499 06500 case TB_GETIMAGELIST: 06501 return TOOLBAR_GetDefImageList (infoPtr, wParam); 06502 06503 case TB_GETINSERTMARK: 06504 return TOOLBAR_GetInsertMark (infoPtr, (TBINSERTMARK*)lParam); 06505 06506 case TB_GETINSERTMARKCOLOR: 06507 return TOOLBAR_GetInsertMarkColor (infoPtr); 06508 06509 case TB_GETITEMRECT: 06510 return TOOLBAR_GetItemRect (infoPtr, wParam, (LPRECT)lParam); 06511 06512 case TB_GETMAXSIZE: 06513 return TOOLBAR_GetMaxSize (infoPtr, (LPSIZE)lParam); 06514 06515 /* case TB_GETOBJECT: */ /* 4.71 */ 06516 06517 case TB_GETPADDING: 06518 return TOOLBAR_GetPadding (infoPtr); 06519 06520 case TB_GETRECT: 06521 return TOOLBAR_GetRect (infoPtr, wParam, (LPRECT)lParam); 06522 06523 case TB_GETROWS: 06524 return TOOLBAR_GetRows (infoPtr); 06525 06526 case TB_GETSTATE: 06527 return TOOLBAR_GetState (infoPtr, wParam); 06528 06529 case TB_GETSTRINGA: 06530 return TOOLBAR_GetStringA (infoPtr, wParam, (LPSTR)lParam); 06531 06532 case TB_GETSTRINGW: 06533 return TOOLBAR_GetStringW (infoPtr, wParam, (LPWSTR)lParam); 06534 06535 case TB_GETSTYLE: 06536 return TOOLBAR_GetStyle (infoPtr); 06537 06538 case TB_GETTEXTROWS: 06539 return TOOLBAR_GetTextRows (infoPtr); 06540 06541 case TB_GETTOOLTIPS: 06542 return TOOLBAR_GetToolTips (infoPtr); 06543 06544 case TB_GETUNICODEFORMAT: 06545 return TOOLBAR_GetUnicodeFormat (infoPtr); 06546 06547 case TB_HIDEBUTTON: 06548 return TOOLBAR_HideButton (infoPtr, wParam, LOWORD(lParam)); 06549 06550 case TB_HITTEST: 06551 return TOOLBAR_HitTest (infoPtr, (LPPOINT)lParam); 06552 06553 case TB_INDETERMINATE: 06554 return TOOLBAR_Indeterminate (infoPtr, wParam, LOWORD(lParam)); 06555 06556 case TB_INSERTBUTTONA: 06557 case TB_INSERTBUTTONW: 06558 return TOOLBAR_InsertButtonT(infoPtr, wParam, (TBBUTTON*)lParam, 06559 uMsg == TB_INSERTBUTTONW); 06560 06561 /* case TB_INSERTMARKHITTEST: */ /* 4.71 */ 06562 06563 case TB_ISBUTTONCHECKED: 06564 return TOOLBAR_IsButtonChecked (infoPtr, wParam); 06565 06566 case TB_ISBUTTONENABLED: 06567 return TOOLBAR_IsButtonEnabled (infoPtr, wParam); 06568 06569 case TB_ISBUTTONHIDDEN: 06570 return TOOLBAR_IsButtonHidden (infoPtr, wParam); 06571 06572 case TB_ISBUTTONHIGHLIGHTED: 06573 return TOOLBAR_IsButtonHighlighted (infoPtr, wParam); 06574 06575 case TB_ISBUTTONINDETERMINATE: 06576 return TOOLBAR_IsButtonIndeterminate (infoPtr, wParam); 06577 06578 case TB_ISBUTTONPRESSED: 06579 return TOOLBAR_IsButtonPressed (infoPtr, wParam); 06580 06581 case TB_LOADIMAGES: 06582 return TOOLBAR_LoadImages (infoPtr, wParam, (HINSTANCE)lParam); 06583 06584 case TB_MAPACCELERATORA: 06585 case TB_MAPACCELERATORW: 06586 return TOOLBAR_MapAccelerator (infoPtr, wParam, (UINT*)lParam); 06587 06588 case TB_MARKBUTTON: 06589 return TOOLBAR_MarkButton (infoPtr, wParam, LOWORD(lParam)); 06590 06591 case TB_MOVEBUTTON: 06592 return TOOLBAR_MoveButton (infoPtr, wParam, lParam); 06593 06594 case TB_PRESSBUTTON: 06595 return TOOLBAR_PressButton (infoPtr, wParam, LOWORD(lParam)); 06596 06597 case TB_REPLACEBITMAP: 06598 return TOOLBAR_ReplaceBitmap (infoPtr, (LPTBREPLACEBITMAP)lParam); 06599 06600 case TB_SAVERESTOREA: 06601 return TOOLBAR_SaveRestoreA (infoPtr, wParam, (LPTBSAVEPARAMSA)lParam); 06602 06603 case TB_SAVERESTOREW: 06604 return TOOLBAR_SaveRestoreW (infoPtr, wParam, (LPTBSAVEPARAMSW)lParam); 06605 06606 case TB_SETANCHORHIGHLIGHT: 06607 return TOOLBAR_SetAnchorHighlight (infoPtr, (BOOL)wParam); 06608 06609 case TB_SETBITMAPSIZE: 06610 return TOOLBAR_SetBitmapSize (infoPtr, wParam, lParam); 06611 06612 case TB_SETBUTTONINFOA: 06613 case TB_SETBUTTONINFOW: 06614 return TOOLBAR_SetButtonInfo (infoPtr, wParam, (LPTBBUTTONINFOW)lParam, 06615 uMsg == TB_SETBUTTONINFOW); 06616 case TB_SETBUTTONSIZE: 06617 return TOOLBAR_SetButtonSize (infoPtr, lParam); 06618 06619 case TB_SETBUTTONWIDTH: 06620 return TOOLBAR_SetButtonWidth (infoPtr, lParam); 06621 06622 case TB_SETCMDID: 06623 return TOOLBAR_SetCmdId (infoPtr, wParam, lParam); 06624 06625 case TB_SETDISABLEDIMAGELIST: 06626 return TOOLBAR_SetDisabledImageList (infoPtr, wParam, (HIMAGELIST)lParam); 06627 06628 case TB_SETDRAWTEXTFLAGS: 06629 return TOOLBAR_SetDrawTextFlags (infoPtr, wParam, lParam); 06630 06631 case TB_SETEXTENDEDSTYLE: 06632 return TOOLBAR_SetExtendedStyle (infoPtr, lParam); 06633 06634 case TB_SETHOTIMAGELIST: 06635 return TOOLBAR_SetHotImageList (infoPtr, wParam, (HIMAGELIST)lParam); 06636 06637 case TB_SETHOTITEM: 06638 return TOOLBAR_SetHotItem (infoPtr, wParam); 06639 06640 case TB_SETIMAGELIST: 06641 return TOOLBAR_SetImageList (infoPtr, wParam, (HIMAGELIST)lParam); 06642 06643 case TB_SETINDENT: 06644 return TOOLBAR_SetIndent (infoPtr, wParam); 06645 06646 case TB_SETINSERTMARK: 06647 return TOOLBAR_SetInsertMark (infoPtr, (TBINSERTMARK*)lParam); 06648 06649 case TB_SETINSERTMARKCOLOR: 06650 return TOOLBAR_SetInsertMarkColor (infoPtr, lParam); 06651 06652 case TB_SETMAXTEXTROWS: 06653 return TOOLBAR_SetMaxTextRows (infoPtr, wParam); 06654 06655 case TB_SETPADDING: 06656 return TOOLBAR_SetPadding (infoPtr, lParam); 06657 06658 case TB_SETPARENT: 06659 return TOOLBAR_SetParent (infoPtr, (HWND)wParam); 06660 06661 case TB_SETROWS: 06662 return TOOLBAR_SetRows (infoPtr, wParam, (LPRECT)lParam); 06663 06664 case TB_SETSTATE: 06665 return TOOLBAR_SetState (infoPtr, wParam, lParam); 06666 06667 case TB_SETSTYLE: 06668 return TOOLBAR_SetStyle (infoPtr, lParam); 06669 06670 case TB_SETTOOLTIPS: 06671 return TOOLBAR_SetToolTips (infoPtr, (HWND)wParam); 06672 06673 case TB_SETUNICODEFORMAT: 06674 return TOOLBAR_SetUnicodeFormat (infoPtr, wParam); 06675 06676 case TB_UNKWN45D: 06677 return TOOLBAR_Unkwn45D(hwnd, wParam, lParam); 06678 06679 case TB_SETHOTITEM2: 06680 return TOOLBAR_SetHotItem2 (infoPtr, wParam, lParam); 06681 06682 case TB_SETLISTGAP: 06683 return TOOLBAR_SetListGap(infoPtr, wParam); 06684 06685 case TB_GETIMAGELISTCOUNT: 06686 return TOOLBAR_GetImageListCount(infoPtr); 06687 06688 case TB_GETIDEALSIZE: 06689 return TOOLBAR_GetIdealSize (infoPtr, wParam, lParam); 06690 06691 case TB_UNKWN464: 06692 return TOOLBAR_Unkwn464(hwnd, wParam, lParam); 06693 06694 /* Common Control Messages */ 06695 06696 /* case TB_GETCOLORSCHEME: */ /* identical to CCM_ */ 06697 case CCM_GETCOLORSCHEME: 06698 return TOOLBAR_GetColorScheme (infoPtr, (LPCOLORSCHEME)lParam); 06699 06700 /* case TB_SETCOLORSCHEME: */ /* identical to CCM_ */ 06701 case CCM_SETCOLORSCHEME: 06702 return TOOLBAR_SetColorScheme (infoPtr, (LPCOLORSCHEME)lParam); 06703 06704 case CCM_GETVERSION: 06705 return TOOLBAR_GetVersion (infoPtr); 06706 06707 case CCM_SETVERSION: 06708 return TOOLBAR_SetVersion (infoPtr, (INT)wParam); 06709 06710 06711 /* case WM_CHAR: */ 06712 06713 case WM_CREATE: 06714 return TOOLBAR_Create (hwnd, (CREATESTRUCTW*)lParam); 06715 06716 case WM_DESTROY: 06717 return TOOLBAR_Destroy (infoPtr); 06718 06719 case WM_ERASEBKGND: 06720 return TOOLBAR_EraseBackground (infoPtr, wParam, lParam); 06721 06722 case WM_GETFONT: 06723 return TOOLBAR_GetFont (infoPtr); 06724 06725 case WM_KEYDOWN: 06726 return TOOLBAR_KeyDown (infoPtr, wParam, lParam); 06727 06728 /* case WM_KILLFOCUS: */ 06729 06730 case WM_LBUTTONDBLCLK: 06731 return TOOLBAR_LButtonDblClk (infoPtr, wParam, lParam); 06732 06733 case WM_LBUTTONDOWN: 06734 return TOOLBAR_LButtonDown (infoPtr, wParam, lParam); 06735 06736 case WM_LBUTTONUP: 06737 return TOOLBAR_LButtonUp (infoPtr, wParam, lParam); 06738 06739 case WM_RBUTTONUP: 06740 return TOOLBAR_RButtonUp (infoPtr, wParam, lParam); 06741 06742 case WM_RBUTTONDBLCLK: 06743 return TOOLBAR_RButtonDblClk (infoPtr, wParam, lParam); 06744 06745 case WM_MOUSEMOVE: 06746 return TOOLBAR_MouseMove (infoPtr, wParam, lParam); 06747 06748 case WM_MOUSELEAVE: 06749 return TOOLBAR_MouseLeave (infoPtr); 06750 06751 case WM_CAPTURECHANGED: 06752 return TOOLBAR_CaptureChanged(infoPtr); 06753 06754 case WM_NCACTIVATE: 06755 return TOOLBAR_NCActivate (hwnd, wParam, lParam); 06756 06757 case WM_NCCALCSIZE: 06758 return TOOLBAR_NCCalcSize (hwnd, wParam, lParam); 06759 06760 case WM_NCCREATE: 06761 return TOOLBAR_NCCreate (hwnd, wParam, (CREATESTRUCTW*)lParam); 06762 06763 case WM_NCPAINT: 06764 return TOOLBAR_NCPaint (hwnd, wParam, lParam); 06765 06766 case WM_NOTIFY: 06767 return TOOLBAR_Notify (infoPtr, (LPNMHDR)lParam); 06768 06769 case WM_NOTIFYFORMAT: 06770 return TOOLBAR_NotifyFormat (infoPtr, wParam, lParam); 06771 06772 case WM_PRINTCLIENT: 06773 case WM_PAINT: 06774 return TOOLBAR_Paint (infoPtr, wParam); 06775 06776 case WM_SETFOCUS: 06777 return TOOLBAR_SetFocus (infoPtr); 06778 06779 case WM_SETFONT: 06780 return TOOLBAR_SetFont(infoPtr, (HFONT)wParam, (WORD)lParam); 06781 06782 case WM_SETREDRAW: 06783 return TOOLBAR_SetRedraw (infoPtr, wParam); 06784 06785 case WM_SIZE: 06786 return TOOLBAR_Size (infoPtr); 06787 06788 case WM_STYLECHANGED: 06789 return TOOLBAR_StyleChanged (infoPtr, (INT)wParam, (LPSTYLESTRUCT)lParam); 06790 06791 case WM_SYSCOLORCHANGE: 06792 return TOOLBAR_SysColorChange (); 06793 06794 case WM_THEMECHANGED: 06795 return theme_changed (hwnd); 06796 06797 /* case WM_WININICHANGE: */ 06798 06799 case WM_CHARTOITEM: 06800 case WM_COMMAND: 06801 case WM_DRAWITEM: 06802 case WM_MEASUREITEM: 06803 case WM_VKEYTOITEM: 06804 return SendMessageW (infoPtr->hwndNotify, uMsg, wParam, lParam); 06805 06806 /* We see this in Outlook Express 5.x and just does DefWindowProc */ 06807 case PGM_FORWARDMOUSE: 06808 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 06809 06810 default: 06811 if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg)) 06812 ERR("unknown msg %04x wp=%08lx lp=%08lx\n", 06813 uMsg, wParam, lParam); 06814 return DefWindowProcW (hwnd, uMsg, wParam, lParam); 06815 } 06816 } 06817 06818 06819 VOID 06820 TOOLBAR_Register (void) 06821 { 06822 WNDCLASSW wndClass; 06823 06824 ZeroMemory (&wndClass, sizeof(WNDCLASSW)); 06825 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS; 06826 wndClass.lpfnWndProc = ToolbarWindowProc; 06827 wndClass.cbClsExtra = 0; 06828 wndClass.cbWndExtra = sizeof(TOOLBAR_INFO *); 06829 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 06830 wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); 06831 wndClass.lpszClassName = TOOLBARCLASSNAMEW; 06832 06833 RegisterClassW (&wndClass); 06834 } 06835 06836 06837 VOID 06838 TOOLBAR_Unregister (void) 06839 { 06840 UnregisterClassW (TOOLBARCLASSNAMEW, NULL); 06841 } 06842 06843 static HIMAGELIST TOOLBAR_InsertImageList(PIMLENTRY **pies, INT *cies, HIMAGELIST himl, INT id) 06844 { 06845 HIMAGELIST himlold; 06846 PIMLENTRY c = NULL; 06847 06848 /* Check if the entry already exists */ 06849 c = TOOLBAR_GetImageListEntry(*pies, *cies, id); 06850 06851 /* If this is a new entry we must create it and insert into the array */ 06852 if (!c) 06853 { 06854 PIMLENTRY *pnies; 06855 06856 c = Alloc(sizeof(IMLENTRY)); 06857 c->id = id; 06858 06859 pnies = Alloc((*cies + 1) * sizeof(PIMLENTRY)); 06860 memcpy(pnies, *pies, ((*cies) * sizeof(PIMLENTRY))); 06861 pnies[*cies] = c; 06862 (*cies)++; 06863 06864 Free(*pies); 06865 *pies = pnies; 06866 } 06867 06868 himlold = c->himl; 06869 c->himl = himl; 06870 06871 return himlold; 06872 } 06873 06874 06875 static VOID TOOLBAR_DeleteImageList(PIMLENTRY **pies, INT *cies) 06876 { 06877 int i; 06878 06879 for (i = 0; i < *cies; i++) 06880 Free((*pies)[i]); 06881 06882 Free(*pies); 06883 06884 *cies = 0; 06885 *pies = NULL; 06886 } 06887 06888 06889 static PIMLENTRY TOOLBAR_GetImageListEntry(const PIMLENTRY *pies, INT cies, INT id) 06890 { 06891 PIMLENTRY c = NULL; 06892 06893 if (pies != NULL) 06894 { 06895 int i; 06896 06897 for (i = 0; i < cies; i++) 06898 { 06899 if (pies[i]->id == id) 06900 { 06901 c = pies[i]; 06902 break; 06903 } 06904 } 06905 } 06906 06907 return c; 06908 } 06909 06910 06911 static HIMAGELIST TOOLBAR_GetImageList(const PIMLENTRY *pies, INT cies, INT id) 06912 { 06913 HIMAGELIST himlDef = 0; 06914 PIMLENTRY pie = TOOLBAR_GetImageListEntry(pies, cies, id); 06915 06916 if (pie) 06917 himlDef = pie->himl; 06918 06919 return himlDef; 06920 } 06921 06922 06923 static BOOL TOOLBAR_GetButtonInfo(const TOOLBAR_INFO *infoPtr, NMTOOLBARW *nmtb) 06924 { 06925 if (infoPtr->bUnicode) 06926 return TOOLBAR_SendNotify(&nmtb->hdr, infoPtr, TBN_GETBUTTONINFOW); 06927 else 06928 { 06929 CHAR Buffer[256]; 06930 NMTOOLBARA nmtba; 06931 BOOL bRet = FALSE; 06932 06933 nmtba.iItem = nmtb->iItem; 06934 nmtba.pszText = Buffer; 06935 nmtba.cchText = 256; 06936 ZeroMemory(nmtba.pszText, nmtba.cchText); 06937 06938 if (TOOLBAR_SendNotify(&nmtba.hdr, infoPtr, TBN_GETBUTTONINFOA)) 06939 { 06940 int ccht = strlen(nmtba.pszText); 06941 if (ccht) 06942 MultiByteToWideChar(CP_ACP, 0, nmtba.pszText, -1, 06943 nmtb->pszText, nmtb->cchText); 06944 06945 nmtb->tbButton = nmtba.tbButton; 06946 bRet = TRUE; 06947 } 06948 06949 return bRet; 06950 } 06951 } 06952 06953 06954 static BOOL TOOLBAR_IsButtonRemovable(const TOOLBAR_INFO *infoPtr, int iItem, const CUSTOMBUTTON *btnInfo) 06955 { 06956 NMTOOLBARW nmtb; 06957 06958 /* MSDN states that iItem is the index of the button, rather than the 06959 * command ID as used by every other NMTOOLBAR notification */ 06960 nmtb.iItem = iItem; 06961 memcpy(&nmtb.tbButton, &btnInfo->btn, sizeof(TBBUTTON)); 06962 06963 return TOOLBAR_SendNotify(&nmtb.hdr, infoPtr, TBN_QUERYDELETE); 06964 } Generated on Sun May 27 2012 04:17:35 for ReactOS by
1.7.6.1
|