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