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