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