ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

toolbar.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.