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