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