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