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